diff --git a/static/js/proxyMapper.js b/static/js/proxyMapper.js index 57881de..58b8798 100644 --- a/static/js/proxyMapper.js +++ b/static/js/proxyMapper.js @@ -9,28 +9,81 @@ (function($) { 'use strict'; - var ProxyMapper = function(mapping, data, options) { + var ProxyMapper = function(mapping, constructionInstruction, data, options) { + var that = this; + this.itemsToBeMapped = Object.keys(constructionInstruction); + this.constructionInstruction = constructionInstruction; this.mapping = mapping; + + //this.mapping = { + // dates: ["l", 0], + // index: { + // '@labels': [0], + // '@dates': [0] + // }, + // //labels: ["l", 1, "l", 0], + // labels: [], + // //values: ["@dates,l", "{1}", "@labels,l", "{1}"] + // values: ["@dates,l", "{1}", "@labels"] + //} + + + this.data = data; + + this.result = {}; + + var funcs = {}; + this.fillKey; + this.labelKey = []; + this.valueKey; + this.itemsToBeMapped.forEach(function(item) { + funcs[item] = new Function('value', 'datum', 'return value'); + let ci = constructionInstruction[item]; + + if (ci.strategy !== undefined && ci.strategy == 'date') { // only 1 key can be a fill key + that.fillKey = item; + } + else if (ci.strategy !== undefined && ci.strategy == 'label') { // multiple keys can be label key + that.labelKey.push(item); + } + else if (ci.strategy !== undefined && ci.strategy == 'value') { // only 1 key can be value key + that.valueKey = item; + } + + // init default type for wanted key + let s = ci.instructions.split('.'); + if (s.length >= 2 && s[0] === '' && s[1] !== '') { + let p_res, p_key; + let c_res = that.result; + s.slice(1).forEach(function(k) { + if (k[0] === '@') { + return false; + } + c_res[k] = {}; + p_res = c_res; + p_key = k; + c_res = c_res[k]; + }); + if (p_key !== undefined) { + p_res[p_key] = []; + } + } + }); + this._default_options = { fillValue: 0, - functions: { - dates: function (value, datum) {return value;}, - labels: function (value, datum) {return value;}, - values: function (value, datum) {return value;} - }, - prefillData: { - dates: [], - labels: [] - }, + functions: funcs, datum: false // the tree data to walk in parallel }; this.options = $.extend({}, this._default_options, options); - this.result = {}; - - this.result.dates = []; this.mappingI2 = {}; + this.mappingToIndexes = {}; + this.itemsToBeMapped.forEach(function(item) { + that.mappingToIndexes[item] = {}; + }); + this.perform_mapping(); return this.result; }; @@ -39,49 +92,95 @@ constructor: ProxyMapper, perform_mapping: function(data) { - if (this.mapping.dates.length > 0) { - for (var x of this.options.prefillData.dates) { this.result['dates'].push(x); } - this.c_dates(this.data, this.mapping.dates); // probe and fetch all dates + var that = this; + var fk = this.fillKey; + var lk = this.labelKey; + var vk = this.valueKey; + + /* fill key is processed first */ + if (fk !== undefined && this.mapping[fk].length > 0) { + this.apply_strategy(fk); } + // prepare fill array let fillArray = []; - for (var i=0; i 0) { - this.c_labels(this.data, this.mapping.labels); // probe and fetch all labels + + // inject prefill data + for (let keyname in this.options.prefillData) { + let p_data = this.options.prefillData[keyname]; + let subkeys = {}; + subkeys[keyname] = p_data; + this.addFromInstruction(keyname, fillArray.slice(0), subkeys, true); + //this.i1_prefill = x; } - //if (this.mapping.labels.length > 0 && this.mapping.values.length > 0) { - if (Object.keys(this.result).length > 1 && this.mapping.values.length > 0) { - this.c_values(this.data, this.mapping.values); // fetch values and overwrite default values - for (var k in this.result) { - this.result[k] = this.result[k].filter(function(n){ return n != undefined }); + // inject prefill data + //for (var x of this.options.prefillData.labels) { + // this.result[x] = fillArray.slice(0); + // this.i1_prefill = x; + //} + + //if (this.mapping.labels.length > 0) { + // this.c_labels(this.data, this.mapping.labels); // probe and fetch all labels + //} + lk.forEach(function(labelK) { + if (that.mapping[labelK].length > 0) { + that.apply_strategy(labelK); + } + }); + + //if (Object.keys(this.result).length > 1 && this.mapping.values.length > 0) { + //if (Object.keys(that.result).length > 0 && that.mapping[vk].length > 0) { + if (Object.keys(that.result).length > 1 && that.mapping[vk].length > 0) { + that.apply_strategy(vk); + for (var k in that.result) { // filter out undefined value + let res = that.result[k]; + if (res !== undefined && !that.isObject(res)) { // if object, picking is likely to be incoherent + let filtered = res.filter(function(n){ return n != undefined }); + that.result[k] = filtered; + } } } }, - c_dates: function(intermediate, instructions) { + + apply_strategy: function(keyname) { + let strategy = this.constructionInstruction[keyname].strategy; + if (strategy == 'date') { + this.c_dates(this.data, this.mapping[keyname], keyname); // probe and fetch all dates + } else if (strategy == 'label') { + this.c_labels(this.data, this.mapping[keyname], keyname); // probe and fetch all labels + } else if (strategy == 'value') { + this.c_values(this.data, this.mapping[keyname], keyname); // fetch values and overwrite default values + } else { + console.log('Invalid mapping strategy'); + } + }, + + c_dates: function(intermediate, instructions, keyname) { var that = this; var matchingFun = function (intermediate, instructions, additionalData) { let index = instructions; let val = intermediate[index]; - if (that.mappingI2[val] === undefined) { - that.mappingI2[val] = that.result['dates'].length; - let nval = that.options.functions.dates(val, additionalData.datum); - that.result['dates'].push(nval); + if (that.mappingToIndexes[keyname][val] === undefined) { + //that.mappingToIndexes[keyname][val] = that.result['dates'].length; + that.mappingToIndexes[keyname][val] = that.result[keyname].length; + //let nval = that.options.functions.dates(val, additionalData.datum); + let nval = that.options.functions[keyname](val, additionalData.datum); + that.addFromInstruction(keyname, nval, {}, false); } }; this.iter(intermediate, instructions, matchingFun, { datum: this.options.datum }); }, - c_labels: function(intermediate, instructions, valuesLength) { + c_labels: function(intermediate, instructions, keyname) { var that = this; var matchingFun = function (intermediate, instructions, additionalData) { let reg = /\{(\w+)\}/; @@ -90,7 +189,7 @@ instructions = res[1]; } let index = instructions; - if (index == 'l') { // labels are the keys themself + if (index == 'l') { // labels are the keys themselves for (let label in intermediate) { let val = []; for (var i=0; i 0 ) { + this.options.toBeMappedList = Object.keys(this.options.toBeMapped); + if (this.options.toBeMappedList.length > 0 ) { this.instructions = {}; this.prefillData = {}; var that = this; - this.options.toBeMapped.forEach(function(item, index) { + this.options.toBeMappedList.forEach(function(item, index) { that.instructions[item] = []; - that.prefillData[item] = []; + //that.prefillData[item] = []; that.itemColors.set(item, that.options.itemColors[index]); }); @@ -612,10 +614,29 @@ //var instructions = this.compute_mapping_instructions(paths); //this.add_instruction(instructions); + this.unset_related(); this.add_prefill_data([c_label]); }, + unset_related: function() { + var that = this; + let curPickingBackup = this.currentPicking; + let refKey = '@'+this.currentPicking; + this.options.toBeMappedList.forEach(function(itemName) { + if (itemName == curPickingBackup) { + return true; + } + let inst = that.options.toBeMapped[itemName].instructions; + let instS = inst.split('.'); + if (instS.indexOf(refKey) > -1) { + that.set_current_mapping_item(itemName); + that.reset_selected(); + } + }); + this.set_current_mapping_item(curPickingBackup); + }, + reset_selected: function() { var that = this; var resNode = that.svg.selectAll(".node circle, .node rect, .node polygon") @@ -682,7 +703,7 @@ var row1 = $(''); var row2 = $(''); var valueHeader; - this.options.toBeMapped.forEach(function(item, index) { + this.options.toBeMappedList.forEach(function(item, index) { var itemColor = that.options.itemColors[index]; var cellH = $(''+item+': '); var cellB2 = $(''); @@ -753,8 +774,9 @@ // if name is empty, select first item not having instructions set_current_mapping_item: function(name) { if (name === undefined) { - for (var entry of this.options.toBeMapped) { - if (this.instructions[entry].length == 0 && this.prefillData[entry].length == 0) { + for (var entry of this.options.toBeMappedList) { + let prefillLength = this.prefillData[entry] !== undefined ? this.prefillData[entry].length : 0; + if (this.instructions[entry].length == 0 && prefillLength == 0) { name = entry; break; } @@ -780,8 +802,10 @@ add_instruction: function(instructions) { this.instructions[this.currentPicking] = instructions; this.currentPickingCell.text(instructions.toString()); - this.set_current_mapping_item(); - this.update_result_tree(); + if (instructions.length != 0) { + this.set_current_mapping_item(); + this.update_result_tree(); + } }, add_prefill_data: function(data) { @@ -819,10 +843,11 @@ fillValue: this.fillValueDomInput.val(), functions: functions, datum: this.root, - prefillData: this.prefillData + prefillData: this.prefillData, }; var adjustedInstructions = this.adjust_instruction(); - var result = new $.proxyMapper(adjustedInstructions, this.data, pm_options); + var constructionInstruction = this.options.toBeMapped; + var result = new $.proxyMapper(adjustedInstructions, constructionInstruction, this.data, pm_options); // destroy and redraw this.treeDivResult[0].innerHTML = ''; @@ -830,22 +855,69 @@ }, adjust_instruction: function() { + var that = this; var adjustedInstructions = $.extend(true, {}, this.instructions); adjustedInstructions.index = {}; var matchingIndex = 0; - var l = this.instructions.labels; - var v = this.instructions.values; - var d = this.instructions.dates; // convert integer index into {index} - for (var i=0; i= 2 && s[0] === '' && s[1] !== '') { + s.slice(1).forEach(function(k) { + if (k.substring(0, 2) === '@@') { + let k_sliced = k.slice(2); + subkeys[k_sliced] = that.instructions[k_sliced]; + } else if (k[0] === '@') { + let k_sliced = k.slice(1); + subkeys[k_sliced] = that.instructions[k_sliced]; + } + }); + } + return false; + } + }); + + for (let keyname in subkeys) { + if (this.options.toBeMapped[keyname].strategy === 'date') { + var d = this.instructions[keyname]; + var d_keyname = keyname; + } else if (this.options.toBeMapped[keyname].strategy === 'label') { + var l = this.instructions[keyname]; + var l_keyname = keyname; + } else { + return false; + } + } + //var l = this.instructions.labels; + //var v = this.instructions.values; + //var d = this.instructions.dates; + // label & value - if (l.length != 0 && v.length != 0) { + if (l !== undefined && l.length != 0 && v.length != 0) { var smaller_array = v.length < l.length ? v : l; var has_matched = false; for (var i=0; i