Customize .y([yScale]) method in dc.js - reduce

I'm trying to create a Bar chart in DC.js. Here I've reduced avg of a field and want to display that on the y-axis. I have no clue on how to do it. Can somebody help me on this?
var dimByChannel = cf.dimension(function(d) { return d.channelUUID; });
var groupByChannel = dimByChannel.group().reduce(reduceAdd, reduceRemove, reduceInitial);
function reduceAdd(p, v) {
p.bytesTxd = p.bytesTxd + v.bytesTxd;
p.avg = (p.bytesTxd/total)*100;
p.count = p.count + 1;
return p;
}
function reduceRemove(p, v) {
p.bytesTxd = p.bytesTxd - v.bytesTxd;
p.avg = (p.bytesTxd/total)*100;
p.count = p.count - 1;
return p;
}
function reduceInitial() {
return {
bytesTxd: 0,
avg: 0,
count: 0
};
}
I've calculated total using reduceSum(). Till now everything is good. Now how to show the reduced avg on y-axis?
chanUtil
.dimension(dimByChannel)
.group(groupByChannel)
.x(d3.scale.ordinal().domain(data.map(function (d) { return d.channelUUID; })))
.xUnits(dc.units.ordinal)
//.y(d3.scale.linear().domain(data.map(function (d) { return d.avg; })))
.yAxisLabel("Utilization %");

Yes, .y() is rather deceptively (or vaguely) named: that one is for the scale, which maps chart coordinates to physical coordinates.
What you want here is .valueAccessor():
.valueAccessor(function(d) { return d.value.avg; })

Related

How to check if the model out of the viewer container?

I made an info card and this card will disappear if the viewer is rotated until the model is not visible. I use isNodevisible but it always returns true.
updateInfoCard() {
if (this.infoCard && this.posModel) {
const pos = this.viewer.worldToClient(this.posModel);
console.log(pos);
this.infoCard.style.left = `${Math.floor(
50 + pos.x - this.infoCard.offsetWidth / 2
)}px`;
this.infoCard.style.top = `${Math.floor(
50 + pos.y - this.infoCard.offsetWidth / 2
)}px`;
const id = this.infoCard.dataset.id;
console.log(this.viewer.isNodeVisible(id));
this.infoCard.style.display = this.viewer.isNodeVisible(id)
? "block"
: "none";
}
}
If I understand your question correctly, you'll probably want to do an intersection test between the camera's frustum and the models's bounding box. That can be done like so:
viewer.addEventListener(Autodesk.Viewing.CAMERA_CHANGE_EVENT, function () {
if (!viewer.model) {
return;
}
const camera = viewer.getCamera();
const matrix = new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
const frustum = new THREE.Frustum().setFromMatrix(matrix);
const bbox = viewer.model.getBoundingBox();
console.log('Model in the view?', frustum.intersectsBox(bbox));
});
And if you only want to check the visibility of a specific element (based on its dbID) of your model, you can compute its bounding box like so:
function objectBounds(model, dbId) {
const tree = model.getInstanceTree();
const frags = model.getFragmentList();
const objectBounds = new THREE.Box3();
tree.enumNodeFragments(dbId, function (fragId) {
const fragBounds = new THREE.Box3();
frags.getWorldBounds(fragId, fragBounds);
objectBounds.union(fragBounds);
}, true);
return objectBounds;
}
The function isNodeVisible returns the visibility status of your node in the scene. If you do something like this.viewer.hide(id, model) your function will return false.
If I well understood what you want to achieve, you want to hide an info card when the associated object is occluded by others objects, so we can't see it from our point of view ?
So I think what you need is to check for occlusion. You can take a look at the checkOcclusion function of this point cloud markup extension made by Philippe Leefsma.
To check for node occlusion, you basically need to raycast from your point of view to the node that you want to check. If you hit something and it's your node, there is no occlusion. If it's not the same node, it's mean that something occlude your node.
checkOcclusion (markup) {
const clientPoint = this.viewer.worldToClient(
markup.point)
const offset = $(this.viewer.container).offset()
const rayCaster = this.pointToRaycaster(
this.viewer.impl.canvas,
this.viewer.impl.camera, {
x: clientPoint.x + offset.left,
y: clientPoint.y + offset.top
})
const hitTest = this.viewer.model.rayIntersect(
rayCaster, true, this.dbIds)
if (hitTest) {
if (hitTest.fragId === markup.fragId) {
const offset = {
x: hitTest.point.x - markup.point.x,
y: hitTest.point.y - markup.point.y,
z: hitTest.point.z - markup.point.z
}
const dist = Math.sqrt(
offset.x * offset.x +
offset.y * offset.y +
offset.z * offset.z)
if (this.options.logOcclusionDist) {
console.log(dist)
}
if (dist < this.options.occlusionDist) {
return false
}
}
return true
}
}

number manipulation in angular

I was trying to convert some number automatically from x=1 to x=00001 so that x takes 5 spaces in total. If x=20.2, I want to format x to be 00020. How can I do that?
I am using html and angularjs. Thanks.
Is this what you want?
function convert(input)
{
var a = Math.floor(input).toString();
return ("00000").substr(0, 5 - a.length) + a;
}
Example:
console.log(convert(20.2)); // 00020
write this filter to achieve the logic
<div>{{number | decimalConvertion:5}}</div>
filter('decimalConvertion', function() {
return function(str, max){
function pad(str, max){
str = str.toString();
return str.length < max ? pad("0" + str, max) : str;
}
return pad(str,8);
};
}
for your reference jsfiddle link

Why can't my html5 class find my observable array contents?

Thanks in advance for any help. I have spent a couple of weeks scouring the web for some insight. I have been developing code for over 50 years but I am a fairly new JavaScript, HTML, knockout. From what I see, this will be great if I can figure out how to make it work. The example given below is only one of the many things I have tried. Please advise.
I have defined two variables as observables, one computed observable, and one observableArray in my view model. Within the document.ready function, I make an Ajax call which returns a json in object notation. ( I checked it in the debugger). When my HTML page displays the observables and computed observables show up properly. The
observable array generates an error (see below) and then displays data obtained from only the first row returned from Ajax. (two were returned).
How do I adjust my code so that all the rows in the Ajax data are shown in the displayed HTML?
Here is the error message that I get:
Uncaught ReferenceError: Unable to process binding "foreach: function (){return cartItems }"
Message: Unable to process binding "text: function (){return itemSubTotal() }"
Message: itemSubTotal is not defined (19:41:39:172 | error, javascript)
Here is my global data for the view model:
var cartDB = "";
var totalPrice = "100";
var cartItems = new Array;
Here is the view model:
var ViewModel =function (){
// direct items ==
this.cartDB = ko.observable(cartDB);
// array itesm
// this.cartItems = ko.observableArray(cartItems);
this.cartItems = ko.mapping.fromJS(cartItems);
//for (var n = 1;n++;n<cartItems.length){ this.cartItems.push(cartItem[n]);}
// computed items
this.totalPriceSv = ko.computed(function(){
return "Total Price*=" + centsToDollars(totalPrice);// todo fix
} ,this);//end totalSvPrice
};// end ViewModel
The data is obtained from the following routine which calls on Ajax.This routine is called once from within document.ready and obtains the expected data on the success callback.
function databaseCart(commandInput, cartDBInput, cartPidInput,logPhpInput) {
var postData = new Array();
postData[0] = commandInput;
postData[1] = cartDBInput;
postData[2] = cartPidInput;
postData[3] = logPhpInput; //debug log on php side
data = null; //for return values
$.ajax({
type: "GET",
url: 'ww_CartProcess.php', //the script to call to get data
data: {data: postData},
dataType: 'json',
success: function(data) {
cartItems = data;
debug = 0;
},
complete: function(data) {
ko.applyBindings(new ViewModel);
return TRUE;
},
error: function(x, e) {//this is the error function for ajax
var xErr = x;
var eErr = e;
ajaxErrorProcessing(xErr, eErr, "addToCart", postData);
}
});
}// end databasecart
Here is the HTML 5 snippet.
<div>
<h1 id="cartTitle">Cart Number: <span data-bind="text: cartDB"> </h1>
<div class ="boxCartItem" data-bind="foreach:cartItems" >
<div class ="boxItemTitle">
<h2 data-bind="text: title()"></h2>
</div><!--boxItemTitle-->
<div class ="cartItemBottom"></div>
</div ><!--class ="boxCartItem"-->
My thanks to the commenters. I still do not know how to add an element to all item rows in an observable array, but this problem was caused by not having the item listed defined. Clue> When multiple errors are presented it is sometimes ( and maybe always) good to work from the bottom up.
The problem can be better stated as : Given a 2 x 17 array (2 rows and 17 columns of independent vars)create an observableArray that contains 2 rows and 17 plus columns consisting of the 17 independent variables (can only be changed in the database or by limited user input) augmented with a large number of computed functions .
1.0 I created an orderModel which contained the ko.computed(functions() for each dependent variable.
function rowOrder(data) {
var self = this;
var model = ko.mapping.fromJS(data, {}, self);
model.imagePathSv = ko.computed(function() {
var category = self.category();
var imageName = self.imageName();
var sv ="";
var sv = "products\\" +category+"\\" + imageName;
return sv;
});//end model.imagePathSv
//original offer
model.origNumValidate = ko.computed(function() {
ans = self.origNum();
if (ans < 0 | ans > 1) {
alert("\
Only onw Original can be pruchased");
ans = 1;
}
self.origNum(ans);
return ans;
});//originalNumValidate
model.origNumLabel = ko.computed(function() {
var sv = "Original..." + centsToDollars(self.origCost());
return sv;
});//end model.origNumLabel
model.origMattedShow = ko.computed(function() {
if (self.origMattedCost() > 0) {
return true;
}
else {
return false;
}
});
model.origMattedLabel = ko.computed(function() {
var sv = "Matting...." + centsToDollars(self.origMattedCost());
return sv;
});
model.origFramedShow = ko.computed(function() {
if (self.origFramedCost() > 0) {
return true;
}
else {
return false;
}
});
model.origFramedLabel = ko.computed(function() {
var sv = "Framing...." + centsToDollars(self.origFramedCost());
return sv;
});
//reproductons offer
model.reproNumValidate = ko.computed(function() {
ans = self.reproNum();
self.reproNum(ans);
return ans;
});
model.reproNumLabel = ko.computed(function() {
var sv = "Reproductions." + centsToDollars(self.reproCost()) + " each";
return sv;
});//end model.reproNumLabel
model.reproMattedShow = ko.computed(function() {
if (self.reproMattedCost() > 0) {
return true;
}
else {
return false;
}
});
model.reproMatted = ko.observable(true);
model.reproMattedLabel = ko.computed(function() {
var sv ="Matting...." +centsToDollars(self.reproMattedCost());
return sv;
});
model.reproFramedShow = ko.computed(function(){
if(self.reproFramedCost()>0){return true;}
else {return false;}
});
model.reproFramed = ko.observable(true);
model.reproFramedLabel = ko.computed(function() {
var sv ="Framing...." +centsToDollars(self.reproFramedCost());
return sv;
});
//pricing subTotals
model.productsSubTotal = ko.computed(function() {
var ans =self.origNum() * self.origCost() + self.reproNum() * self.reproCost();
return ans;
});//end model.productsSubTotal
model.productsSubTotalSv = ko.computed(function() {
return "Products.." +centsToDollars(model.productsSubTotal());
return ans;
});//end model.productsSubTotal
model.mattingSubTotal = ko.computed(function() {
return self.origNum() * self.origMattedCost() + self.reproNum() * self.reproMattedCost();
});//end model.mattingSubTotal
model.mattingSubTotalSv = ko.computed(function() {
return "Matting...." +centsToDollars(model.mattingSubTotal());
});//end model.mattingSubTotal
model.framingSubTotal = ko.computed(function() {
return self.origNum() * self.origFramedCost() + self.reproNum() * self.reproFramedCost();
});//end model.framingSubTotal
model.framingSubTotalSv = ko.computed(function() {
return "Framing...." +centsToDollars(model.framingSubTotal());
});//end model.productsSubTotal
model.rowSubTotal = ko.computed(function() {
return model.productsSubTotal() +model.mattingSubTotal() + model.framingSubTotal();
});//end model.rowsSubTotal
model.rowSubTotalSv = ko.computed(function() {
return "Item Subtotal.." +centsToDollars(model.rowSubTotal());
});//end model.productsSubTotal
};// END rowOrder
2.0 I created a mapping variable as follows:
var mapping = {
create: function(options) {
return new rowOrder(options.data);
}
};
3,0 I created a View Model as follows:
function ViewModel() {
// direct items for whole page
var self = this;
this.cartId = ko.observable(cartDB);
this.cartIdSv = ko.computed(function() {
var sv = "Cart Number: "+ self.cartId();
return sv;
},this);//
this.totalPrice = ko.computed(function() {//to DO COMPUTE
var int = 10000;
return int;
},this);
this.totalPriceSv = ko.computed(function(){
return "Total Price*: " + centsToDollars(this.totalPrice());
},this);
// by row items
this.cartItems = ko.mapping.fromJS(cartItems, mapping);
}// end ViewModel
4.0 In the success call back from ajax :
success: function(data) {
cartItems = data;
ViewModel();
5.0 I put the ko.apply.bindings(new ViewModel) in the ajax complete callback.
The result was that my rather involved page came up as expected with the computed values initially set.
I am still working on how to update this page. I have not been able to get my code to recompute the computed variables when the user clicks or unclicks a checkbox.
I could not have done this without suggestions from the stackOverflow group. Thanks to you all for the posts that I found all over the google.

How can I do this asyn feature in nodejs

I have a code to do some calculation.
How can I write this code in an asyn way?
When query the database, seems we can not get the results synchronously.
So how to implement this kind of feature?
function main () {
var v = 0, k;
for (k in obj)
v += calc(obj[k].formula)
return v;
}
function calc (formula) {
var result = 0;
if (formula.type === 'SQL') {
var someSql = "select value from x = y"; // this SQL related to the formula;
client.query(someSql, function (err, rows) {
console.log(rows[0].value);
// *How can I get the value here?*
});
result = ? // *How can I return this value to the main function?*
}
else
result = formulaCalc(formula); // some other asyn code
return result;
}
Its not possible to return the result of an asynchronous function, it will just return in its own function scope.
Also this is not possible, the result will always be unchanged (null)
client.query(someSql, function (err, rows) {
result = rows[0].value;
});
return result;
Put a callback in the calc() function as second parameter and call that function in the client.query callback with the result
function main() {
calc(formula,function(rows) {
console.log(rows) // this is the result
});
}
function calc(formula,callback) {
client.query(query,function(err,rows) {
callback(rows);
});
}
Now if you want the main to return that result, you also have to put a callback parameter in the main and call that function like before.
I advice you to check out async its a great library to not have to deal with this kind of hassle
Here is a very crude way of implementing a loop to perform a calculation (emulating an asynchronous database call) by using events.
As Brmm alluded, once you go async you have to go async all the way. The code below is just a sample for you to get an idea of what the process in theory should look like. There are several libraries that make handling the sync process for asynch calls much cleaner that you would want to look into as well:
var events = require('events');
var eventEmitter = new events.EventEmitter();
var total = 0;
var count = 0;
var keys = [];
// Loop through the items
calculatePrice = function(keys) {
for (var i = 0; i < keys.length; i++) {
key = keys[i];
eventEmitter.emit('getPriceFromDb', {key: key, count: keys.length});
};
}
// Get the price for a single item (from a DB or whatever)
getPriceFromDb = function(data) {
console.log('fetching price for item: ' + data.key);
// mimic an async db call
setTimeout( function() {
price = data.key * 10;
eventEmitter.emit('aggregatePrice', {key: data.key, price: price, count: data.count});
}, 500);
}
// Agregate the price and figures out if we are done
aggregatePrice = function(data) {
count++;
total += data.price;
console.log('price $' + price + ' total so far $' + total);
var areWeDone = (count == data.count);
if (areWeDone) {
eventEmitter.emit('done', {key: data.key, total: total});
}
}
// We are done.
displayTotal = function(data) {
console.log('total $ ' + data.total);
}
// Wire up the events
eventEmitter.on('getPriceFromDb', getPriceFromDb);
eventEmitter.on('aggregatePrice', aggregatePrice);
eventEmitter.on('done', displayTotal);
// Kick of the calculate process over an array of keys
keys = [1, 2, 3]
calculatePrice(keys);

How do I return the number of rows of a table according to a search criteria in Web SQL?

I have created a database called todo with table name todo having fields like title,date etc. The table is empty right now.
I have defined a function which takes title as parameter and check whether table contains that title or not.
It should return the number of rows.
GetTitle function:
todo.webdb.GetTitle = function(title) {
var db = todo.webdb.db;
db.transaction(function(tx){
tx.executeSql("SELECT title FROM todo WHERE title=?", [title],
loadTitle,
todo.webdb.onError);
});
}
loadTitle Function:
function loadTitle(tx, rs) {
return rs.rows.length;
}
GetTitle Function is called:
row=todo.webdb.GetTitle("Hello");
alert(row);
I get alert 'undefined' it should return 0
I am confused right now how to resolve this issue.
I think the transactions are asynchronous, so you need to callback function to receive the value.
todo.webdb.GetTitle = function(title, callback) {
var db = todo.webdb.db;
db.transaction(function(tx){
tx.executeSql("SELECT title FROM todo WHERE title=?", [title],
(function loadTitle(tx, rs){
callback( rs.rows.length );
}),
todo.webdb.onError);
});
}
todo.webdb.GetTitle( "Hello", function(count){
alert( "count = " + count );
});
Here's an excellent tutorial for more information.
http://blog.darkcrimson.com/2010/05/local-databases/
Update
Don't make functions inside a loop for this main reason.
Both i and title are referencing a value created out of local scope.
So the last value of assigned to both i and title will be displayed.
for (i = 0; i < itemcount; i++) {
alert('i outside if:' + i);
var title = x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
todo.webdb.GetTitle( title, function (count) {
if (!count) {
alert('i inside if:' + i);
alert( title );
}
});
}
Fix:
Generate a function that has the values locked in a closure.
var createTitleCallBack = function( i, title ){
return function (count) {
if (!count) {
alert('i inside if:' + i);
alert( title );
}
};
};
for (i = 0; i < itemcount; i++) {
alert('i outside if:' + i);
var title = x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue;
todo.webdb.GetTitle( title, createTitleCallBack( i, title ) );
}