ExtJS Two and more separators on numberfields - extjs

Tell me, please, how you can use two types of separator digital input field? You can use only one standard methods, but at a different keyboard layout, there is a need to use another, keeping the data in one format, that is the '.'
Input: 10,789 or 10.789
Save: 10.789
I use Ext.form.NumberField for editing integral field.
Part of my code:
var editor = new Ext.ux.grid.RowEditor({
saveText: LANG['update'],
listeners: {
afteredit: function(object, changes, r, rowIndex) {
Ext.MessageBox.alert(LANG['alert_info'], LANG['memory']); }
}
}
});
var userGrid = new Ext.grid.GridPanel({
id: 'status-form',
region:'center',
margins: '5 5 5 5',
store: Gstore,
iconCls: 'icon-grid',
plugins: [editor, summary],
cm: new Ext.grid.ColumnModel([
{header: "ID", width: 30, sortable: true, dataIndex: 'idb', renderer: formatID},
{xtype: 'datecolumn', header: LANG['date'], width: 70, sortable: true, dataIndex: 'date',
groupRenderer: Ext.util.Format.dateRenderer('M Y'),
format: 'd/m/Y',
editor: new Ext.form.DateField({
value: (new Date()).format('d/m/Y'),
//format: 'd/m/Y',
minValue: '01/01/2010',
//minText: 'Please Check Correct Data',
maxValue: (new Date()).format('d/m/Y'),
editable: false
})
},
{header: LANG['title'], width: 150, sortable: true, dataIndex: 'title',
editor: new Ext.form.TextField({}),
summaryType: 'count',
summaryRenderer: function(v, params, data){
return ((v === 0 || v > 1) ? LANG['Tasks']+ ': '+ v: '1 '+LANG['Task']);
}
},
{header: LANG['lenght'], width: 60, sortable: true, dataIndex: 'lenght', renderer: formatKM, align: 'center',
summaryType: 'sum',
summaryRenderer: Ext.util.Format.cifres2,
editor: new Ext.form.NumberField({
allowNegative: false,
decimalPrecision: 2,
//decimalSeparator: ',',
maxValue: 1000
//allowBlank: false
})
},
{header: LANG['time'], width: 30, sortable: true, dataIndex: 'time', align: 'center',
renderer: formatTimeStr,
summaryType: 'sum22',
editor: new Ext.form.NumberField({
//format: 'H:i',
allowNegative: false,
decimalPrecision: 2,
decimalSeparator: ':'
})
},
{header: LANG['vsr'], width: 50, sortable: true, dataIndex: 'vsr', renderer: formatKM, align: 'center',
summaryType: 'average',
summaryRenderer: Ext.util.Format.cifres2,
editor: new Ext.form.NumberField({
allowNegative: false,
decimalPrecision: 2,
maxValue: 100
})
},
{header: LANG['vmax'], width: 50, sortable: true, dataIndex: 'vmax', renderer: formatKM, align: 'center',
summaryType: 'max',
summaryRenderer: Ext.util.Format.cifres2,
editor: new Ext.form.NumberField({
allowNegative: false,
decimalPrecision: 2,
maxValue: 100
})
}, ............

I implemented this with easy way. My method is enable key events of number field and check if pressed key is ',' than add a '.' to value. That is the implementation;
Ext.create('Ext.form.Panel', {
title: 'On The Wall',
width: 300,
bodyPadding: 10,
renderTo: Ext.getBody(),
items: [{
xtype: 'numberfield',
anchor: '100%',
name: 'bottles',
fieldLabel: 'Bottles of Beer',
enableKeyEvents : true,
value: 99,
maxValue: 99,
minValue: 0,
listeners : {
keypress : function(view, e){
if(e.getKey() == 44)
view.setRawValue(view.getRawValue() +'.');
}
}
}]
});

I used this in my project but I don't know it's fit your request.
First, checking the value where it's number and has "." then put proper value based on this condition. If it's not has "." in the value then calling the replace function.
value.match(/^[0-9]+\.?[0-9]*$/) ? Number(value) : Number((value.replace(',', '.')));

The solution is found here: http://habrahabr.ru/post/137966/ (russian lang)
Since there is seen a solution for version> 4.0, and I have worth less had to change the code, replacing the standard JS functions.Vykladyvayu it here, maybe someone will need:
To begin at the header of the page to connect сursor.js
// Author: Diego Perini <dperini#nwbox.com>
var sb = new Array(
'leftbox', 'rightbox', 'scrollLeft', 'scrollRight',
'caretPos', 'maxLength', 'textLength', 'availLength',
'beforeCaret', 'afterCaret', 'selectedText'
)
var leftbox = {};
var rightbox = {};
var scrollLeft = {};
var scrollRight = {};
var caretPos = {};
var maxLength = {};
var textLength = {};
var availLength = {};
var beforeCaret = {};
var afterCaret = {};
var selectedText = {};
/*
for (var i in sb) {
var v = '"var '+sb[i]+' = {}"';
eval(v);
}
*/
var os = 0
var oe = 0
function update(o) {
var t = o.value, s = getSelectionStart(o), e = getSelectionEnd(o)
if (s == os && e == oe) return
caretPos.firstChild.nodeValue = s
maxLength.firstChild.nodeValue = o.getAttribute('maxLength')
textLength.firstChild.nodeValue = t.length
availLength.firstChild.nodeValue = o.getAttribute('maxLength') - t.length
afterCaret.firstChild.nodeValue = t.substring(s).replace(/ /g, '\xa0') || '\xa0'
beforeCaret.firstChild.nodeValue = t.substring(0, s).replace(/ /g, '\xa0') || '\xa0'
selectedText.firstChild.nodeValue = t.substring(s, e).replace(/ /g, '\xa0') || '\xa0'
rightbox.value = scrollRight.firstChild.nodeValue = t.substring(s).replace(/ /g, '\xa0') || '\xa0'
leftbox.value = scrollLeft.firstChild.nodeValue = t.substring(0, s).replace(/ /g, '\xa0') || '\xa0'
os = s
oe = e
return true
}
function setup() {
for (var i in sb) eval(sb[i] + ' = document.getElementById(sb[i])')
update(document.getElementById('textbox'))
}
function getSelectionStart(o) {
if (o.createTextRange) {
var r = document.selection.createRange().duplicate()
r.moveEnd('character', o.value.length)
if (r.text == '') return o.value.length
return o.value.lastIndexOf(r.text)
} else return o.selectionStart
}
function getSelectionEnd(o) {
if (o.createTextRange) {
var r = document.selection.createRange().duplicate()
r.moveStart('character', -o.value.length)
return r.text.length
} else return o.selectionEnd
}
and connect the plugin:
Ext.ns('Ext.ux.form');
/**
* #class Ext.ux.form.NumberInputFilter
* #extends Ext.form.NumberField
* Plugin (ptype = 'numberinputfilter')
* #param allowedDecimalSeparators: ',.:-' and other
* #ptype numberinputfilter
*/
Ext.ux.form.NumberInputFilter = Ext.extend(Ext.form.NumberField, {
initComponent: function(){
Ext.ux.form.NumberInputFilter.superclass.initComponent.call(this);
},
init : function(field) {
if (!(field && field.isXType('numberfield'))) {
return;
}
Ext.apply(field, {
allowedDecimalSeparators : this.allowedDecimalSeparators,
checkValue : function(newChar) {
var raw = this.getRawValue();
var el = Ext.get(this.id).dom;
// functions taken from here http://javascript.nwbox.com/cursor_position/
// and connected to a separate file cursor.js
var start = getSelectionStart(el);
var end = getSelectionEnd(el);
if (start != end) {
// delete the selected text from the expected values
raw = raw.substring(0, start) + raw.substring(end);
}
if (Ext.isEmpty(raw)) {
return (newChar == this.decimalSeparator || (this.minValue < 0) && newChar == '-') || newChar.search('/^\d$/');
}
if (raw.length == this.maxLength) {
return false;
}
if (newChar == this.decimalSeparator && (!this.allowDecimals || raw.indexOf(this.decimalSeparator) != -1)) {
return false;
}
// form the intended meaning
raw = raw.substring(0, start) + newChar + raw.substring(start);
raw = raw.split(new RegExp(this.decimalSeparator.replace("/([-.*+?^${}()|[\]\/\\])/g", "\\$1")));
return (!raw[0] || this.intRe.search(raw[0])) && (!raw[1] || this.decRe.search(raw[1]));
},
filterKeys : function(e){
if (e.ctrlKey && !e.altKey) {
return;
}
var key = e.getKey(),
charCode = String.fromCharCode(e.getCharCode());
if(Ext.isGecko && (e.isNavKeyPress() || key === e.BACKSPACE || (key === e.DELETE && e.button === -1))){
return;
}
if(!Ext.isGecko && e.isSpecialKey() && !charCode){
return;
}
// begin hack
if (charCode != this.decimalSeparator && this.allowedDecimalSeparators.indexOf(charCode) != -1) {
// if the input character is not a decimal point,
                    // But it is one of the alternatives,
                    // Replace it with a decimal point
charCode = this.decimalSeparator;
if (Ext.isIE) {
// in the IE code of the pressed key can be substituted directly
e.browserEvent.keyCode = charCode.charCodeAt(0);
} else if (Ext.isGecko) {
// for gecko-engine slowing Event
e.stopEvent();
// create a new event with the modified code of the pressed key
var newEvent = document.createEvent('KeyEvents');
// Mandatory event must be cancelable
                        // As it can be reversed, if the decimal
                        // Delimiter is entered in the field
newEvent.initKeyEvent(
e.browserEvent.type,
e.browserEvent.bubbles,
true, //cancellable
e.browserEvent.view,
e.browserEvent.ctrlKey,
e.browserEvent.altKey,
e.browserEvent.shiftKey,
e.browserEvent.metaKey,
0, // keyCode
charCode.charCodeAt(0) // charCode
);
e.getTarget().dispatchEvent(newEvent);
// event generated, nothing doing.
return;
} else if (Ext.isWebKit) {
// stopped event
e.stopEvent();
// into webkit initKeyboardEvent dont work, use TextEvent
if (this.checkValue(charCode)) {
var newEvent = document.createEvent('TextEvent');
newEvent.initTextEvent(
'textInput',
e.browserEvent.bubbles,
true,
e.browserEvent.view,
charCode
);
e.getTarget().dispatchEvent(newEvent);
}
return;
}
}
if (!this.checkValue(charCode)) {
e.stopEvent();
}
// end hack
},
updateDecimalPrecision : function(prec, force) {
if (prec == this.decimalPrecision && force !== true) {
return;
}
if (!Ext.isNumber(prec) || prec < 1) {
this.allowDecimals = false;
} else {
this.decimalPrecision = prec;
}
var intRe = '^';
if (this.minValue < 0) {
intRe += '-?';
}
intRe += '\\d' + (Ext.isNumber(this.integerPrecision) ? '{1,' + this.integerPrecision + '}' : '+') + '$';
this.intRe = new RegExp(intRe);
if (this.allowDecimals) {
this.decRe = new RegExp('^\\d{1,' + this.decimalPrecision + '}$');
} else {
delete this.decRe;
}
},
fixPrecision : function(value) {
// support decimalSeparators
if (Ext.isString(value)) {
value = value.replace(new RegExp('[' + (this.allowedDecimalSeparators + this.decimalSeparator).replace("/([-.*+?^${}()|[\]\/\\])/g", "\\$1") + ']'), '.');
}
// end hack
var me = this,
nan = isNaN(value),
precision = me.decimalPrecision;
if (nan || !value) {
return nan ? '' : value;
} else if (!me.allowDecimals || precision <= 0) {
precision = 0;
}
console.info(parseFloat(parseFloat(value).toFixed(precision)));
return parseFloat(parseFloat(value).toFixed(precision));
}
});
field.updateDecimalPrecision(field.decimalPrecision, true);
}
});
Ext.preg('numberinputfilter', Ext.ux.form.NumberInputFilter);
Use any separator, what we like in a digital field, just listing them:
.....
{header: LANG['lenght'], width: 60, sortable: true, dataIndex: 'lenght', renderer: formatKM, align: 'center',
summaryType: 'sum',
summaryRenderer: Ext.util.Format.cifres2,
editor: new Ext.form.NumberField({
allowNegative: false,
decimalPrecision: 2,
plugins: new Ext.ux.form.NumberInputFilter({
allowedDecimalSeparators : ',.-'
}),
maxValue: 1000,
allowBlank: false
})
},
.....

Related

extjs6 update mask message not updating in long running method where chart is being updated with new series

In my extjs6 project I have this long running method. Starting with a loaded store, it groups by 'instrument', then creates an array with each item of that 'instrument', then creates a new store with only that data, then creates a series for a extjs chart, and adds the series to the chart.
there is a ton of data with about 100 instruments and a daily number for 2-3 years of data for each instrument. the process takes a long time and I want to update the mask window to say which instrument is being updated so the user can see what is going on.
How can I update the mask message in the middle of this long running method?
var me = this;
var myMask = Ext.get(me.windowCumulative.getEl()).mask('hello');
var task = new Ext.util.DelayedTask(function () {
//fadeout section
myMask.fadeOut({
duration: 500,
remove: true
});
//convert sql date to date datatype
myStoreTab1.each(function (record) {
record.set('filedate', new Date(record.get('filedate')));
});
myStoreTab1.sort('filedate');
myStoreTab1.group('instrument');
myStoreTab1.getGroups().each(function (group, i) {
var groupName = group._groupKey;
var targetStore = Ext.create('Ext.data.Store', {
model: 'xxx.model.HistoricalInstrumentProfitModel'
});
var records = [];
group.each(function (record) {
records.push(record.copy());
});
targetStore.add(records);
var series = {
type: 'line',
axis: 'left',
xField: 'filedate',
yField: 'cumulativePl',
store: targetStore,
title: groupName,
tooltip: {
trackMouse: true,
renderer: 'onSeriesTooltipRender'
}
};
me.chartTab1.addSeries(series);
//me.chartTab1.redraw();
//me.windowCumulative.setLoading(false);
console.log('added series: ' + groupName);
});
});
task.delay(500);
//debugger;
//me.chartTab1.redraw();
UPDATE...
for every group I run this
function DoMask(step, panel, countGroups, group, chart) {
setTimeout(function () {
var groupName = group._groupKey;
var targetStore = Ext.create('Ext.data.Store', {
model: 'xxx.model.HistoricalInstrumentProfitModel'
});
var records = [];
group.each(function (record) {
records.push(record.copy());
});
targetStore.suspendEvents();
targetStore.add(records);
var series = {
type: 'line',
axis: 'left',
xField: 'filedate',
yField: 'cumulativePl',
store: targetStore,
title: groupName,
tooltip: {
trackMouse: true,
renderer: 'onSeriesTooltipRender'
}
};
chart.addSeries(series);
console.log('added series: ' + groupName);
console.log(count);
panel.mask('step : ' + count);
if (count == countGroups) {
chart.resumeEvents();
chart.resumeLayouts();
chart.resumeChartLayout();
chart.redraw();
panel.unmask();
}
count = count + 1;
}, 500);
}
Take a look at these two ways to present the progress to the user:
Here is the FIDDLE
Ext.application({
name: 'Fiddle',
launch: function () {
var count;
var p = Ext.create('Ext.ProgressBar', {
width: 300,
textTpl: 'my Progress {value*100}%'
});
var window = Ext.create('Ext.window.Window', {
title: 'Progress',
modal:true,
hidden:true,
closable:false,
items:[
p
]
});
var panel = Ext.create('Ext.panel.Panel', {
title: 'teste',
height: 400,
renderTo: Ext.getBody(),
items: [{
xtype: 'button',
text: 'START LONG PROCESS MASK',
handler: function () {
count = 0;
this.up('panel').mask('Start');
DoMask(count);
}
}, {
xtype: 'button',
text: 'START LONG PROGRESS BAR',
handler: function () {
count = 0;
window.show();
DoProgress(count);
}
}]
});
function DoMask(step) {
setTimeout(function () {
panel.mask('step : ' + step);
count++;
if (count <= 10) {
DoMask(count);
} else {
panel.unmask();
}
}, 500);
}
function DoProgress(step) {
setTimeout(function () {
p.setValue(step/10);
count++;
if (count <= 10) {
DoProgress(count);
} else {
window.hide();
}
}, 500);
}
}
});

Integrating Sparkline High Chart in Angular Nested UI Grid

I am trying to integrate spark line high chart in Angularjs nested UI grid. I have implemented Highcharts.SparkLine function within row expand event in UI grid. Is there any function like rowExpandComplete in Angular UiGrid?
gridApi.expandable.on.rowExpandedStateChanged($scope, function (row) {
if (row.isExpanded) {
var str = "10,12,45,34";
$scope.template = "<table id='table-sparkline'><tbody id='tbody-sparkline'><tr><td data-sparkline=" + str + "> </td> </tr> </tbody></table>";
row.entity.subGridOptions = {
columnDefs: [
{ name: 'name' },
{ name: 'gender', cellTemplate: $scope.template },
{ name: 'company' }
]
};
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/100.json')
.success(function (data) {
row.entity.subGridOptions.data = data;
/**
* Create a constructor for sparklines that takes some sensible defaults and merges in the individual
* chart options. This function is also available from the jQuery plugin as $(element).highcharts('SparkLine').
*/
Highcharts.SparkLine = function (a, b, c) {
var hasRenderToArg = typeof a === 'string' || a.nodeName,
options = arguments[hasRenderToArg ? 1 : 0],
defaultOptions = {
chart: {
renderTo: (options.chart && options.chart.renderTo) || this,
backgroundColor: null,
borderWidth: 0,
type: 'area',
margin: [2, 0, 2, 0],
width: 120,
height: 20,
style: {
overflow: 'visible'
},
// small optimalization, saves 1-2 ms each sparkline
skipClone: true
},
title: {
text: ''
},
credits: {
enabled: false
},
xAxis: {
labels: {
enabled: false
},
title: {
text: null
},
startOnTick: false,
endOnTick: false,
tickPositions: []
},
yAxis: {
endOnTick: false,
startOnTick: false,
labels: {
enabled: false
},
title: {
text: null
},
tickPositions: [0]
},
legend: {
enabled: false
},
tooltip: {
backgroundColor: null,
borderWidth: 0,
shadow: false,
useHTML: true,
hideDelay: 0,
shared: true,
padding: 0,
positioner: function (w, h, point) {
return { x: point.plotX - w / 2, y: point.plotY - h };
}
},
plotOptions: {
series: {
animation: false,
lineWidth: 1,
shadow: false,
states: {
hover: {
lineWidth: 1
}
},
marker: {
radius: 1,
states: {
hover: {
radius: 2
}
}
},
fillOpacity: 0.25
},
column: {
negativeColor: '#910000',
borderColor: 'silver'
}
}
};
options = Highcharts.merge(defaultOptions, options);
return hasRenderToArg ?
new Highcharts.Chart(a, options, c) :
new Highcharts.Chart(options, b);
};
var start = +new Date(),
$tds = $('td[data-sparkline]'),
fullLen = $tds.length,
n = 0;
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
$td = $($tds[i]);
stringdata = $td.data('sparkline');
arr = stringdata.split('; ');
data = $.map(arr[0].split(', '), parseFloat);
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('th').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
n += 1;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
// Print a feedback on the performance
if (n === fullLen) {
$('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
}
}
}
doChunk();
});
}
});
But it is triggering only for second time when we expand the row. Can any one tell me where I am going wrong. I have created the plunker for the same.

ExtJS 6. Pickerfield with treepanel

I do not know the right way of creating a treepanel pickerfield. Now I do it like so:
{
xtype:'pickerfield',
width:'34%',
emptyText: 'Choose layer',
createPicker: function(){
return Ext.create('Ext.tree.Panel',{
hidden: true,
floating: true,
minHeight: 300,
pickerField: this,
root: {
text: 'Root',
expanded: true,
children:[{
text: 'Standard',
expanded: true,
children: [{
text: 'Open Street Map',
checked: true,
leaf: true,
itemId: 'OMS'
},{
text: 'MapQuest',
leaf: false,
children:[{
text: 'Road',
leaf:true,
checked: false,
itemId: 'MapQuest',
val: 'osm'
},{
text: 'Satellite',
leaf:true,
checked: false,
itemId: 'MapQuest',
val: 'sat'
},{
text: 'Hybride',
leaf:true,
checked: false,
itemId: 'MapQuest',
val: 'hyb'
}]
}]
}]
}
});
}
}
It works partially. When I first hit the picker, it shows me a treepanel, but when I expand some nodes (leaf=false), then it gets closed. The same happens, when I check a tree leaf - I do not want that, because, the user is allowed to check multiple nodes. Beside, even when I check some leaves, the value of the picker stays unchanged (it keeps showing emptyText value). So, how to fix all this?
You can use following sample:
Ext.define('Ext.ux.TreeCombo',
{
extend: 'Ext.form.field.Picker',
alias: 'widget.treecombo',
tree: false,
constructor: function(config)
{
this.addEvents(
{
"itemclick" : true
});
this.listeners = config.listeners;
this.callParent(arguments);
},
records: [],
recursiveRecords: [],
ids: [],
selectChildren: true,
canSelectFolders: true,
multiselect: false,
displayField: 'text',
valueField: 'id',
treeWidth: 300,
matchFieldWidth: false,
treeHeight: 400,
masN: 0,
recursivePush: function(node, setIds)
{
var me = this;
me.addRecRecord(node);
if(setIds) me.addIds(node);
node.eachChild(function(nodesingle)
{
if(nodesingle.hasChildNodes() == true)
{
me.recursivePush(nodesingle, setIds);
}
else
{
me.addRecRecord(nodesingle);
if(setIds) me.addIds(nodesingle);
}
});
},
recursiveUnPush: function(node)
{
var me = this;
me.removeIds(node);
node.eachChild(function(nodesingle)
{
if(nodesingle.hasChildNodes() == true)
{
me.recursiveUnPush(nodesingle);
}
else me.removeIds(nodesingle);
});
},
addRecRecord: function(record)
{
var me = this;
for(var i=0,j=me.recursiveRecords.length;i<j;i++)
{
var item = me.recursiveRecords[i];
if(item)
{
if(item.getId() == record.getId()) return;
}
}
me.recursiveRecords.push(record);
},
afterLoadSetValue: false,
setValue: function(valueInit)
{
if(typeof valueInit == 'undefined') return;
var me = this,
tree = this.tree,
values = (valueInit == '') ? [] : valueInit.split(','),
valueFin = [];
inputEl = me.inputEl;
if(tree.store.isLoading())
{
me.afterLoadSetValue = valueInit;
}
if(inputEl && me.emptyText && !Ext.isEmpty(values))
{
inputEl.removeCls(me.emptyCls);
}
if(tree == false) return false;
var node = tree.getRootNode();
if(node == null) return false;
me.recursiveRecords = [];
me.recursivePush(node, false);
me.records = [];
Ext.each(me.recursiveRecords, function(record)
{
var id = record.get(me.valueField),
index = values.indexOf(''+id);
if(me.multiselect == true) record.set('checked', false);
if(index != -1)
{
valueFin.push(record.get(me.displayField));
if(me.multiselect == true) record.set('checked', true);
me.addRecord(record);
}
});
me.value = valueInit;
me.setRawValue(valueFin.join(', '));
me.checkChange();
me.applyEmptyText();
return me;
},
getValue: function()
{
return this.value;
},
getSubmitValue: function()
{
return this.value;
},
checkParentNodes: function(node)
{
if(node == null) return;
var me = this,
checkedAll = true;
node.eachChild(function(nodesingle)
{
var id = nodesingle.getId(),
index = me.ids.indexOf(''+id);
if(index == -1) checkedAll = false;
});
if(checkedAll == true)
{
me.addIds(node);
me.checkParentNodes(node.parentNode);
}
else
{
me.removeIds(node);
me.checkParentNodes(node.parentNode);
}
},
initComponent: function()
{
var me = this;
me.tree = Ext.create('Ext.tree.Panel',
{
alias: 'widget.assetstree',
hidden: true,
minHeight: 300,
rootVisible: (typeof me.rootVisible != 'undefined') ? me.rootVisible : true,
floating: true,
useArrows: true,
width: me.treeWidth,
autoScroll: true,
height: me.treeHeight,
store: me.store,
listeners:
{
load: function(store, records)
{
if(me.afterLoadSetValue != false)
{
me.setValue(me.afterLoadSetValue);
}
},
itemclick: function(view, record, item, index, e, eOpts)
{
me.itemTreeClick(view, record, item, index, e, eOpts, me)
}
}
});
if(me.tree.getRootNode().get('checked') != null) me.multiselect = true;
this.createPicker = function()
{
var me = this;
return me.tree;
};
this.callParent(arguments);
},
addIds: function(record)
{
var me = this;
if(me.ids.indexOf(''+record.getId()) == -1) me.ids.push(''+record.get(me.valueField));
},
removeIds: function(record)
{
var me = this,
index = me.ids.indexOf(''+record.getId());
if(index != -1)
{
me.ids.splice(index, 1);
}
},
addRecord: function(record)
{
var me = this;
for(var i=0,j=me.records.length;i<j;i++)
{
var item = me.records[i];
if(item)
{
if(item.getId() == record.getId()) return;
}
}
me.records.push(record);
},
removeRecord: function(record)
{
var me = this;
for(var i=0,j=me.records.length;i<j;i++)
{
var item = me.records[i];
if(item && item.getId() == record.getId()) delete(me.records[i]);
}
},
itemTreeClick: function(view, record, item, index, e, eOpts, treeCombo)
{
var me = treeCombo,
checked = !record.get('checked');//it is still not checked if will be checked in this event
if(me.multiselect == true) record.set('checked', checked);//check record
var node = me.tree.getRootNode().findChild(me.valueField, record.get(me.valueField), true);
if(node == null)
{
if(me.tree.getRootNode().get(me.valueField) == record.get(me.valueField)) node = me.tree.getRootNode();
else return false;
}
if(me.multiselect == false) me.ids = [];
//if it can't select folders and it is a folder check existing values and return false
if(me.canSelectFolders == false && record.get('leaf') == false)
{
me.setRecordsValue(view, record, item, index, e, eOpts, treeCombo);
return false;
}
//if record is leaf
if(record.get('leaf') == true)
{
if(checked == true)
{
me.addIds(record);
}
else
{
me.removeIds(record);
}
}
else //it's a directory
{
me.recursiveRecords = [];
if(checked == true)
{
if(me.multiselect == false)
{
if(me.canSelectFolders == true) me.addIds(record);
}
else
{
if(me.canSelectFolders == true)
{
me.recursivePush(node, true);
}
}
}
else
{
if(me.multiselect == false)
{
if(me.canSelectFolders == true) me.recursiveUnPush(node);
else me.removeIds(record);
}
else me.recursiveUnPush(node);
}
}
//this will check every parent node that has his all children selected
if(me.canSelectFolders == true && me.multiselect == true) me.checkParentNodes(node.parentNode);
me.setRecordsValue(view, record, item, index, e, eOpts, treeCombo);
},
fixIds: function()
{
var me = this;
for(var i=0,j=me.ids.length;i<j;i++)
{
if(me.ids[i] == 'NaN') me.ids.splice(i, 1);
}
},
setRecordsValue: function(view, record, item, index, e, eOpts, treeCombo)
{
var me = treeCombo;
me.fixIds();
me.setValue(me.ids.join(','));
me.fireEvent('itemclick', me, record, item, index, e, eOpts, me.records, me.ids);
if(me.multiselect == false) me.onTriggerClick();
}
});
var storeMenu = Ext.create('Ext.data.TreeStore',
{
root:
{
text: 'Root',
id: '0',
expanded: true,
children:
[
{id: '1', text: 'First node', leaf: false, children:
[
{id: '3', text: 'First child node', leaf: true},
{id: '4', text: 'Second child node', leaf: true}
]
},
{id: '2', text: 'Second node', leaf: true}
]
},
folderSort: false
});
Ext.onReady(function() {
Ext.create('Ext.ux.TreeCombo', {
margin:10,
width:120,
height: 10,
treeHeight: 10,
treeWidth: 240,
renderTo: 'treecombo3',
store: storeMenu,
selectChildren: false,
canSelectFolders: true
,itemTreeClick: function(view, record, item, index, e, eOpts, treeCombo)
{
var id = record.data.id;
}
});
});

Extjs Gauge Change ColorSet by value

Is there anyway to change the extjs gauge chart's colorset by changing value?
var gauge = {
xtype: 'chart',
style: 'background:#fff',
animate: true,
store: GaugeStore,
insetPadding: 25,
axes: [{
title: 'Performans (%)',
type: 'gauge',
position: 'gauge',
minimum: 0,
maximum: 100,
steps: 10,
margin: 4
}],
series: [{
type: 'gauge',
field: 'percentagesla',
donut: 40,
colorSet:['',''],
renderer: function (sprite, record, attr, index, store)
{
var value = record.get("percentagesla"), color;
if (value >= 95) { this.colorSet = ['#fff000','ddd']; }
else if (value < 85) { this.colorSet = ['#ffcc00', 'ddd']; }
else { this.colorSet = ['#ffaa00', 'ddd']; }
}
}]
}
Renderer function does not work for setting colorset. How can i handle this problem?
Thanks.
use this
renderer: function (sprite, record, attr, index, store) {
if (attr.fill == this.colorSet[1]) return Ext.apply(attr, { fill: attr.fill });
var value = record.get("SLA"),
color;
if (value >= 95) {
color = "#0000ff";
} else if (value < 85) {
color = "#00ff00";
} else {
color = "#ff0000";
}
return Ext.apply(attr, { fill: color });
}

I wrote CardBoard Rally sdk 2 app to which I added filter but I want to add two different filter, one for releases and one for backlog

I wrote CardBoard Rally sdk 2 app to which I added filter which apply to Backlog and Releases too. But I want to add two different filters, one for releases and one for backlog
See in image attached, u can see one column for Backlog and other for releases
So I should be able to say Now filter Backlog features, and Now filter Releases features
Below is my some of code snippet
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
autoScroll: true,
all_releases: [],
items:[{ xtype: 'container', itemId: 'filter_box', padding: 5},{xtype:'container',itemId:'button_box', padding: 5}],
logger: new Rally.technicalservices.logger(),
launch: function() {
//var allReleases = this._getReleases();
this._drawCardBoard(this, filters= null);
this.down('#button_box').add({
xtype: 'rallybutton',
text: 'Filter Criteria',
itemId: 'run-button',
scope: this,
handler: this._run,
margin: '0 0 0 10'
});
this.down('#button_box').add({
xtype: 'rallybutton',
text: 'Prev',
itemId: 'prev-button',
scope: this,
handler: this._setPrevReleaseDate,
margin: '0 0 0 100'
});
this.down('#button_box').add({
xtype: 'rallybutton',
text: 'Next',
itemId: 'next-button',
scope: this,
handler: this._setNextReleaseDate,
margin: '0 0 0 650'
});
},
_setPrevReleaseDate: function() {
if (this.globalVar == undefined) {
this.globalVar = new Date();
} else {
this.globalVar = new Date(this.globalVar);
};
this.globalVar = Rally.util.DateTime.formatWithDefault(Ext.Date.subtract(this.globalVar, Ext.Date.DAY, 224));
this._drawCardBoard(this, filters= null);
},
_setNextReleaseDate: function() {
if (this.globalVar == undefined) {
this.globalVar = new Date();
} else {
this.globalVar = new Date(this.globalVar);
};
this.globalVar = Rally.util.DateTime.formatWithDefault(Ext.Date.add(this.globalVar, Ext.Date.DAY, 224));
this._drawCardBoard(this, filters= null);
},
_getFilters: function(records) {
var filters = null;
if (records.length >= 1) {
if (records[0].data.PortfolioItemTypeName == "MMF") {
filters = Ext.create('Rally.data.QueryFilter',{
property: 'Parent',
operator: '=',
value: records[0].get("_ref")
});
} else if (records[0].data.PortfolioItemTypeName == "Epic") {
filters = Ext.create('Rally.data.QueryFilter',{
property: 'Parent.Parent',
operator: '=',
value: records[0].get("_ref")
});
} else if (records[0].data.PortfolioItemTypeName == "Program") {
filters = Ext.create('Rally.data.QueryFilter',{
property: 'Parent.Parent.Parent',
operator: '=',
value: records[0].get("_ref")
});
}
for ( var i=1;i<records.length;i++ ) {
if (records[i].data.PortfolioItemTypeName == "MMF") {
filters = filters.or(Ext.create('Rally.data.QueryFilter',{
property: 'Parent',
operator: '=',
value: records[i].get("_ref")
}));
} else if (records[i].data.PortfolioItemTypeName == "Epic") {
filters = filters.or(Ext.create('Rally.data.QueryFilter',{
property: 'Parent.Parent',
operator: '=',
value: records[i].get("_ref")
}));
} else if (records[i].data.PortfolioItemTypeName == "Program") {
filters = filters.or(Ext.create('Rally.data.QueryFilter',{
property: 'Parent.Parent.Parent',
operator: '=',
value: records[i].get("_ref")
}));
}
}
}
return filters;
},
_drawCardBoard: function(that, filters){
if (that.cardboard) {
that.cardboard.destroy();
};
var me = that;
if (filters == null) {
filters = [];
}
me.cardboard = Ext.create('Rally.ui.cardboard.CardBoard',{
types: ['PortfolioItem/Feature'],
attribute: 'Release',
config: {globalVar: this.globalVar},
columnConfig: {
xtype: 'rallycardboardcolumn',
displayField: 'Name',
valueField: '_ref',
plugins: [
{ptype:'rallycolumndropcontroller'},
{ptype:'rallycardboardcardrecordprocessor'},
{ptype:'tscolumnheaderupdater'} /*,
{ptype:'tscolumnheaderupdater', field_to_aggregate: 'LeafStoryPlanEstimateTotal'}*/
],
storeConfig: {
filters: filters,
context: this.getContext().getDataContext()
}
},
addColumn: function (columnConfig, index) {
console.log(columnConfig, index,"columnConfig, index");
var column = this._createColumnDefinition(columnConfig);
Ext.Array.insert(this.columnDefinitions, Ext.isNumber(index) ? index : this.columnDefinitions.length, [column]);
return column;
},
cardConfig: {
editable: true,
showIconsAndHighlightBorder: false,
showReadyIcon: true,
showBlockedIcon: true,
showColorIcon: true,
showPlusIcon: true,
showGearIcon: true,
fields: [
'FormattedID',
'Name',
'Parent',
'ReleaseDate',
'ReleaseStartDate',
{ name: 'Project', renderer: me._renderProject },
{ name: 'PercentDoneByStoryPlanEstimate' },
{ name: 'PreliminaryEstimate', fetch: ['PreliminaryEstimate', 'Name'], renderTpl: Ext.create('Ext.XTemplate', '{PreliminaryEstimate.Name}')},
{ name: 'LeafStoryPlanEstimateTotal', fetch: ['LeafStoryPlanEstimateTotal'], renderTpl: Ext.create('Ext.XTemplate', 'Plan Estimate Total: {LeafStoryPlanEstimateTotal}')}
],
},
listeners: {
beforeShow: this._onTeamMembersLoaded,
added: function(card,container){
//card.set('DisplayColor', "blue");
me.logger.log(this,card,container);
},
fieldClick: function(eOpts) {
me.logger.log(this,eOpts);
if ( eOpts == "PercentDoneByStoryPlanEstimate" ) {
me._showDoneTooltip(eOpts,this);
}
},
scope: this
}
});
_getLocalReleases: function(retrievedColumns, today_iso) {
var me = this;
if (today_iso == undefined) {
today_iso = Rally.util.DateTime.toIsoString(new Date(),false);
}
var filters = [{property:'ReleaseDate',operator:'>',value:today_iso}];
var iteration_names = [];
Ext.create('Rally.data.WsapiDataStore',{
model:me.attribute,
autoLoad: true,
filters: filters,
context: { projectScopeUp: false, projectScopeDown: false },
sorters: [
{
property: 'ReleaseDate',
direction: 'ASC'
}
],
//limit: Infinity,
pageSize: 4,
//buffered: true,
//purgePageCount: 4,
fetch: ['Name','ReleaseStartDate','ReleaseDate','PlannedVelocity'],
listeners: {
load: function(store,records) {
Ext.Array.each(records, function(record){
var start_date = Rally.util.DateTime.formatWithNoYearWithDefault(record.get('ReleaseStartDate'));
var end_date = Rally.util.DateTime.formatWithNoYearWithDefault(record.get('ReleaseDate'));
iteration_names.push(record.get('Name'));
//iteration_names.push(record.get('ReleaseDate'));
retrievedColumns.push({
value: record,
_planned_velocity: 0,
_missing_estimate: false,
columnHeaderConfig: {
headerTpl: "{name}<br/>{start_date} - {end_date}",
headerData: {
name: record.get('Name'),
start_date: start_date,
end_date: end_date,
planned_velocity: 0,
missing_estimate: false
}
}
});
});
this._getAllReleases(retrievedColumns,iteration_names);
},
scope: this
}
});
},
applyLocalFilters: function() {
this.applyFilters(this.localFilters);
},
_getAllReleases: function(retrievedColumns,iteration_names, today_iso) {
var me = this;
if (today_iso == undefined) {
today_iso = Rally.util.DateTime.toIsoString(new Date(),false);
}
var filters = [{property:'ReleaseDate',operator:'>',value:today_iso}];
Ext.create('Rally.data.WsapiDataStore',{
model:me.attribute,
autoLoad: true,
filters: filters,
sorters: [
{
property: 'ReleaseDate',
direction: 'ASC'
}
],
fetch: ['Name','Project','PlannedVelocity'],
listeners: {
load: function(store,records) {
Ext.Array.each(records, function(record){
var planned_velocity = record.get('PlannedVelocity') || 0;
var index = Ext.Array.indexOf(iteration_names[0],record.get('Name'));
if (planned_velocity == 0 ) {
retrievedColumns[index+1]._missing_estimate = true;
}
retrievedColumns[index+1]._planned_velocity += planned_velocity;
});
this.fireEvent('columnsretrieved',this,retrievedColumns);
this.columnDefinitions = [];
_.map(retrievedColumns,this.addColumn,this);
this._renderColumns();
},
scope: this
}
});
},
_createColumnDefinition: function (columnConfig) {
var config = Ext.merge({
enableCrossColumnRanking: this.enableCrossColumnRanking
}, this.columnConfig, columnConfig);
var enableRanking = this.enableRanking;
if (this.context) {
var workspace = this.context.getWorkspace();
if (workspace) {
enableRanking = enableRanking && workspace.WorkspaceConfiguration.DragDropRankingEnabled;
}
}
var listenersConfig = {
ready: this._onColumnReady,
select: this._onCardSelect,
deselect: this._onCardDeselect,
cardinvalid: this._onCardInvalid,
cardready: this._onCardReady,
scope: this
};
if (!this.serverSideFiltering) {
listenersConfig.filter = this.applyLocalFilters;
}
Ext.merge(config, {
cardConfig: Ext.clone(this.cardConfig),
columnHeaderConfig: Ext.clone(this.columnHeaderConfig),
model: this.models,
attribute: this.attribute,
storeConfig: Ext.clone(this.storeConfig),
enableRanking: enableRanking,
filterCollection: this.filterCollection ? this.filterCollection.clone() : undefined,
ownerCardboard: this,
listeners: listenersConfig,
ddGroup: this.ddGroup
});
if (this.readOnly) {
config.dropControllerConfig = false;
}
//merge configs, unioning collections
var cardConfig = config.cardConfig;
if (columnConfig.cardConfig) {
Ext.Object.merge(cardConfig, columnConfig.cardConfig);
cardConfig.fields = Ext.Array.merge(columnConfig.cardConfig.fields || [], this.cardConfig.fields || []);
}
var storeConfig = config.storeConfig;
if (columnConfig.storeConfig) {
Ext.Object.merge(storeConfig, columnConfig.storeConfig);
storeConfig.filters = Ext.Array.merge(columnConfig.storeConfig.filters || [], this.storeConfig.filters || []);
}
console.log("columnConfig", Ext.clone(columnConfig));
console.log("storeConfig", Ext.clone(storeConfig));
return Ext.widget(config.xtype, config);
},
});
Ext.override(Rally.ui.cardboard.Card,{
_setupPlugins: function() {
var cardContentRightPlugin = {ptype: 'rallycardcontentright'};
this.plugins.push(cardContentRightPlugin);
this.plugins.push({ptype: 'rallycardcontentleft'});
if (this.record.get('updatable')) {
if (this.editable) {
this.addCls('editable');
this.plugins.push({ptype: 'rallycardediting'});
var predicateFn = Rally.predicate.RecordPredicates.hasField('PlanEstimate');
if (predicateFn(this.record) && Ext.Array.contains(this.getFields(), 'PlanEstimate')) {
cardContentRightPlugin.showPlanEstimate = true;
}
if (this.enableValidationUi) {
this.plugins.push({ptype: 'rallycardvalidation'});
this.plugins.push({ptype: 'rallycardvalidationui', notificationFieldNames: ['PlanEstimate']});
}
}
if (this.showIconsAndHighlightBorder) {
this.plugins.push({
ptype: 'rallycardicons',
showMenus: this.showIconMenus,
showColorPopover: this.showColorPopover
});
}
}
if (this.showAge > -1) {
this.plugins.push({ptype: 'rallycardage'});
}
this.plugins.push({ptype:'tscardreleasealignment'});
}
}),
Ext.override(Rally.ui.cardboard.Column,{
getStoreFilter: function(model) {
var property = this.attribute;
var value = this.getValue();
if ( this.attribute == "Release" ) {
property = "Release.Name";
if ( value ) {
value = value.get('Name');
}
}
return {
property:property,
operator: '=',
value: value
};
},
isMatchingRecord: function(record) {
var recordValue = record.get(this.attribute);
if (recordValue) {
recordValue = recordValue.Name;
}
var columnValue = this.getValue();
if ( columnValue ) {
columnValue = columnValue.get('Name');
}
return (columnValue === recordValue );
},
addCard: function(card, index, highlight) {
var record = card.getRecord();
var target_value = this.getValue();
if ( target_value && typeof(target_value.get) === "function" ) {
target_value = this.getValue().get('_ref');
}
record.set(this.attribute,target_value);
if (target_value) {
record.set("PlannedStartDate",this.getValue().get('ReleaseStartDate'));
record.set("PlannedEndDate",this.getValue().get('ReleaseDate'));
} else {
record.set("PlannedStartDate",null);
record.set("PlannedEndDate",null);
}
if (!Ext.isNumber(index)) {
//find where it should go
var records = Ext.clone(this.getRecords());
records.push(record);
this._sortRecords(records);
var recordIndex = 0;
for (var iIndex = 0, l = records.length; iIndex < l; iIndex++) {
var i = records[iIndex];
if (i.get("ObjectID") === record.get("ObjectID")) {
recordIndex = iIndex;
break;
}
}
index = recordIndex;
}
this._renderCard(card, index);
if (highlight) {
card.highlight();
}
this.fireEvent('addcard');
card.fireEvent('ready', card);
},

Resources