How do you create an extension to Chart.js? - chart.js

I have created a new chart type:
Chart.types.Line.extend({
name: "LineWithRectangle",
draw: function () {
Chart.types.Line.prototype.draw.apply(this, arguments);
var startPoint = this.datasets[0].points[this.options.startIndex]
var endPoint = this.datasets[0].points[this.options.endIndex]
var scale = this.scale
this.chart.ctx.fillStyle = "#808080";
ctx.globalAlpha = 0.2;
this.chart.ctx.fillRect(startPoint.x,
scale.startPoint,
endPoint.x - startPoint.x,
scale.endPoint - scale.startPoint);
ctx.stroke();
ctx.globalAlpha = 1;
this.chart.ctx.textAlign = 'center';
this.chart.ctx.fillText("EVENT DAY",
startPoint.x + (endPoint.x - startPoint.x) / 2,
scale.startPoint + 20);
}
});
I placed this code in another file and referenced in the page :
<script src="~/lib/charts-js/Chart.js" type="text/javascript"></script>
<script src="~/lib/charts-js/ChartExtensions.js" type="text/javascript"></script>
But when I try to use it I'm not getting a chart object in the debugger:
new Chart(ctx.children[0].getContext("2d")).LineWithRectangle(data, { pointHitDetectionRadius: 0.05, animation: false, startIndex: start, endIndex: end })
Chrome is not reporting a ChartType object like it does for built in chart types but says "not available".
What am I doing wrong here?

Your code expects different values for ctx in the main code vs. your extension. In your main code it seems like a DOM node and in your extension you are using it as a context.
Just add
var ctx = this.chart.ctx;
after Chart.types.Line.prototype.draw.apply(this, arguments); and it should work. If not, check if your main code variables are all defined with correct values (start, end and ctx)

Related

How can i add additional Data(Type) to chart.js

i had already done adding a click handler to each Segment of my doughnut chart with adding the following Code :
$("#myChart").click(
function(evt){
var activePoints = myNewChart.getSegmentsAtEvent(evt);
var chartelementid = activePoints[0].label;
alert(chartelementid);
//$('.details div').css("display", "none");
//$('#' + chartelementid).show();
}
);
This works fine, when finished it should display an additional Div with Details for this segment.
Unfortunality my labels are more then just Single Words, so i'm struggeling to create div ID's with the same name...
My Idea is to add to every Segment an additional Data like value,label, etc. so it could be an ID. but if i just add the ID information to the Segment it will not exist as variable.
Add DataType:
var dataImprove = [
{
value: 30,
color:"#001155",
highlight: "#1c2f7c",
label: "KnowHow Erhalt / Transfer & Aufbau",
id:"test"
}
]
where can i add in chart.js an additional dataType like shown above my ID to be accessible in the DOM?
kind regards Marco
As an alternative pass a JSON string as your label, then intercept to render. For example:
var canvas = document.getElementById(id);
var d = canvas.getContext("2d");
var chart = new Chart(d).Pie(json, {
segmentStrokeWidth: 1,
tooltipTemplate: "<%=label%>", //default the label
customTooltips: function (tooltip) {
// Hide if no tooltip
if (!tooltip) {
return;
}
var tooltipObj = JSON.parse(tooltip.text);
// etc
already found : between line 999 and 1023 in chart.js before drawing - i've added the line
id: ChartElements[0].id,
so the Data with the name ID is in the DOM avaiable.

How to build an endless animation with famo.us?

I'm willing to build an endless animation using famous (for example an endless rolling gear or a randomly shaken surface). Should I write a custom Transitionable with an infinite duration or there is something smarter to achieve this ?
I would recommend using Modifiers transformFrom method to define a position or rotation based on time. This allows you to set a transform that will be updated on every tick of the engine, but will be controlled via actual time.
Here is an example of that..
Hope it helps!
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var Transform = require('famous/core/Transform');
var Modifier = require('famous/core/Modifier');
var context = Engine.createContext();
var surface = new Surface({
size:[200,200],
content: "Hello",
properties: {
lineHeight:"200px",
color:"white",
textAlign:"center",
backgroundColor:'green'
}
})
surface.mod = new Modifier({
origin: [0.5,0.5],
align:[0.5,0.5]
});
var startTime = (new Date).getTime();
surface.mod.transformFrom(function(){
var currentTime = (new Date).getTime();
var rotation = (currentTime - startTime) / 360.0;
return Transform.rotate(0,0,rotation);
});
context.add(surface.mod).add(surface);
The answer is to use Transitionables
First you use use Transitionable.set(destination, {duration: VALUE})
Each Engine 'prerender' (every frame), you use Transitionable.get() to update a Modifier Transform
At the end of the Transitionable, it will run a callback to update the new destination
this.transit = new Transitionable(0);
// ------- when i say twerk, you twerk ----->
var _createWheelMod = function() {
var _setWheelModRotation = function() {
Engine.on("prerender", function() {
this.wheelMod.setTransform(Transform.rotate(0, 0, this.transit.get()));
}.bind(this));
};
// ------------ charge lasers ------->
var _setDestination = function() {
this.transit.set(100 + this.transit.get(), {duration: 2e5},
_setDestination.bind(this)); // callback when the transition has finished
};
_setWheelModRotation.call(this);
_setDestination.call(this);
};

Dojo: set store for template filteringselect

in order to get familiar with dojo I'm working on a test project which consists of the following components:
data grid (created declaratively), filled with JSON data; clicking on a line will open a dialog containing a form (works)
form (created from template), with several input fields, filled with data from the grid store (works)
FilteringSelect (part of form) (doesn't work, no content)
The FilteringSelect contains dynamic data. In order to keep data traffic low, I thought it wise to get this data when the whole page is loaded and to pass it into the template initialization function.
In fact, I don't really know how to assign the store to the FilteringSelect.
Any help would be greatly appreciated.
Here's my code. I shorten it to the what I consider relevant parts so that it's easier to understand.
Grid Part:
var data_list = fetchPaymentProposalList.fetch();
/*create a new grid*/
var grid = new DataGrid({
id: 'grid',
store: store,
structure: layout
});
// store for FilteringSelect
var beneficiaryList = FetchBeneficiaryList.fetch();
var beneficiaryListStore = new Memory({
identifier : "id",
data : beneficiaryList
});
return {
// function to create dialog with form
instantiate:
function(idAppendTo) {
/*append the new grid to the div*/
grid.placeAt(idAppendTo);
/*Call startup() to render the grid*/
grid.startup();
grid.resize();
dojo.connect(grid, "onRowClick", grid, function(evt) {
var rowItem = this.getItem(evt.rowIndex);
var itemID = rowItem.id[0];
var store = this.store;
var paymentProposalForm = new TmpPaymentProposalForm();
paymentProposalForm._init(store.getValue(rowItem, "..."), ..., beneficiaryListStore);
});
}
};
The beneficiarylist comes as something like this:
return { 12: { id : 1, name : "ABC" }};
The FilteringSelect in the template looks like this:
<input data-dojo-type="dijit/form/FilteringSelect" name="recipient" id="recipient" value="" data-dojo-props="" data-dojo-attach-point="recipientNode" />
Template Init Code looks like this:
_init: function(..., beneficiaryListStore) {
this.recipientNode.set("labelAttr", "name");
this.recipientNode.set("searchAttr", "name");
// here should come the store assignment, I guess???
var dia = new Dialog({
content: this,
title: "ER" + incoming_invoice,
style: "width: 600px; height: 400px;"
});
dia.connect(dia, "hide", function(e){
dijit.byId(dia.attr("id")).destroyRecursive();
});
dia.show();
}
For anyone who's interested, here's my solution:
var beneficiaryList = FetchBeneficiaryList.fetch();
var beneficiaryData = {
identifier : "id",
items : []
};
for(var key in beneficiaryList)
{
if(beneficiaryList.hasOwnProperty(key))
{
beneficiaryData.items.push(lang.mixin({ id: key }, beneficiaryList[key]));
}
}
var beneficiaryListStore = new Memory({
identifier : "id",
data : beneficiaryData
});
That did the trick

Zoom n the partcular country n raphael.js

. I am very new to raphael.js.I have done a europe map using t.I'm
able to change color while mouseover.But I just want to zoom the
particular country while t s clicked.It must be like zoom t the
clicked country with some specific points n the country
script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var rsr = Raphael('map', '631', '686');
var attr = {
fill: "#C0C0C0",
stroke: "#666",
"stroke-width": 1,
"stroke-linejoin": "round"
};
var world = {};
world.Portugal = rsr.path("56,0.133-1.32,0.527c-0.661,1.321-0.264,2.906-0.925,4.228c-0.528,1.057-3.698,5.415-3.434,6.868
c0.132,0.526,1.056-0.529,1.584-0.529c0.792-0.132,1.585,0.133,2.377,0c0.396,0,0.792-0.396,1.188-0.264
c2.113,0.527,8.981,5.019,9.906,4.887c0.396,0,4.49-1.981,4.754-2.113C57.876,621.536,58.537,621.536,59.197,621.536L59.197,621.536
z").attr(attr);;
world.Spain = rsr.path(" M194.57,552.728c0.924,0.396,1.981,0.63.434,4.754c-,0,0.792,0
c0.661,0.133,1.453,0.133,1.849,0.528c0.66,0.528,0.264,1.717,0.924,2.113v0.132C190.74,552.066,190.476,553.916,194.57,552.728
L194.57,552.728z").attr(attr);
var current = null;
for(var country in world) {
(function (st, country) {
country = country.toLowerCase();
st[0].style.cursor = "pointer";
st[0].onmouseover = function () {
st.animate({fill:"#808080", stroke: "#ccc"}, 500);
};
st[0].onmouseout = function () {
st.animate({fill: "#C0C0C0", stroke: "#666"}, 500);
st.toFront();
R.safari();
};
st[0].onclick = function () {
st.animate({width: "500px"}, 'slow');//THS DOES NOT WORk
};
})(world[country], country);
}
});
can anyone help me how to do ths???please
..
You are trying to set the 'width' attribute which the path, in fact, does not possess. The way to go is to set the 'transform' attribute as here. You might also have to set the scaling origin, since the path you are scaling is not centered at zero (cf. Raphael center of scale in transform method).

problem with my tableView GROUPED

Here I have a problem with my tableView I want to insert text into each row of the table
can you help me please
here is the code
// this sets the background color of the master UIView (when there are no windows/tab groups on it)
Titanium.UI.setBackgroundColor('white');
// create tab group
var tabGroup = Titanium.UI.createTabGroup({
});
// create base UI tab and root window
var win1= Titanium.UI.createWindow({
title:'',
tabBarHidden: true,
barColor:'black',
backgroundColor:'white'
});
var tab= Ti.UI.createTab({
title:'Connexion ',
window:win1
});
//
// This is a test that is meant to verify that a row object can have a header
// and the table view has no table view header - the header should be displayed
var win = Titanium.UI.currentWindow;
var inputData = [
{title:'Pseudo/email :', header:'Connexion ......'},
{title:'Password :'},
{title:'Créer votre compte',hasChild:true, header:'not yet registered ?'},
];
var tableView = Titanium.UI.createTableView({
data:inputData,
style:Titanium.UI.iPhone.TableViewStyle.GROUPED
});
win1.add(tableView);
tabGroup.addTab(tab);
// open tab group-----------------------------------------
tabGroup.open();
win1.open();
that's what I did right now but I have a problem with the title of my table and then I add another table.
there are also some ouci with the cursor which moves in the mid-line titles
here is the code
var win1= Titanium.UI.createWindow({
title:'',
tabBarHidden: true,
barColor:'black',
backgroundColor:'white'
});
var view = Titanium.UI.createView({
backgroundColor: "#FFFEEE"
});
var row1 = Ti.UI.createTableViewRow({
height:'auto',
selectionStyle:Ti.UI.iPhone.TableViewCellSelectionStyle.NONE
});
var label1 = Titanium.UI.createLabel({
text:'Pseudo/e-mail :',
left: 10
});
var usernametf = Ti.UI.createTextField({
left: 100,
right:10,
//hintText: 'Pseudo/email :',
//textAlign:"right",
borderStyle: Ti.UI.INPUT_BORDERSTYLE_NONE
});
var row2 = Ti.UI.createTableViewRow({
height:'auto',
selectionStyle:Ti.UI.iPhone.TableViewCellSelectionStyle.NONE
});
var label2 = Titanium.UI.createLabel({
text:'Mot de passe :',
left: 10
});
var passwordtf = Ti.UI.createTextField({
left: 100,
//textAlign:"right",
//hintText: 'password',
right:30,
passwordMask:true,
borderStyle: Ti.UI.INPUT_BORDERSTYLE_NONE
});
row1.add(label1);
row1.add(usernametf);
row2.add(label2);
row2.add(passwordtf);
var data = [row1,row2];
var table = Ti.UI.createTableView
({
data:data,
style: Ti.UI.iPhone.TableViewStyle.GROUPED
});
view.add(table);
win1.add(view);
win1.open();
I let you know that I really began with Appcelerator
Is there any reason why you wouldn't just use textfields? You could then just grab the values on button press and insert.
Kitchen Sink example link
https://github.com/appcelerator/titanium_mobile/blob/master/demos/KitchenSink/Resources/examples/textfield_events.js
Another example of a screen like this would be the Tweetanium App https://github.com/appcelerator/tweetanium
Whether you use textfields or tableviews there are several ways to work with the Ti Database object.
Two common ways would be:
1) You can loop through your inputData object and insert. Below are a few examples.
https://github.com/appcelerator/titanium_mobile/blob/master/demos/KitchenSink/Resources/examples/database_2.js
https://github.com/appcelerator/titanium_mobile/blob/master/demos/KitchenSink/Resources/examples/database_3.js
2) You can use the tableview object itself or a wrapper similar to this example https://github.com/kwhinnery/Persistence
I would recommend using textfields if possible.