I would like to know if it is possible to retrieve the new path after animation, I tried :
var p =
canevas.path("M0,0,100,20").animate({transform:"t100,100"},500,"none",function
() {alert(this.attr("path"));})
but alert alerts me the original path without taking into account the transformation .
Is there a way to do this ?
Thank you
V.Bonnet
You can use the Raphael.transformPath method to get the path with the transformation 'baked in'. To use your example:
var paper = Raphael(10, 10, 300, 300);
var line = paper.path("M0,0,100,20");
line.animate({ transform: "t100,100" }, 500, "none", function() {
var transform = this.attr('transform');
var transformedPath = Raphael.transformPath(this.attr('path'), transform);
console.log("original path:", this.attr('path').toString());
console.log("transform:", transform.toString());
console.log("new path:", transformedPath.toString());
})
This will yield:
original path: M0,0L100,20
transform: t100,100
new path: M100,100C100,100,200,120,200,120
See it in action here: http://jsfiddle.net/seeligd/HCUey/3/
When translating in Raphael 2.x it doesn't modify the path, it adds a transformation such as...
<path fill="none" stroke="#000000" d="M0,0L100,20" transform="matrix(1,0,0,1,100,100)"></path>
I recall that Raphael 1.x used to modify the path, but this is no longer true. To find out how the element was transformed you can try...
var p = canevas.path("M0,0,100,20").animate({transform:"t100,100"},500,"none",function () {alert(this.attr("transform"));})
and it will return t100t100 which you have to parse manually.
Related
I am trying to create a line chart plugin that will draw reference letters under some points. To do so, the plugin uses a custom afterDatasetsDraw function to perform the drawing. However, I am unable to find a way to pass in the reference letters for the desired points. Below is an example of what I'm trying to achieve with the red circled letters.
Does anyone have an idea on how to pass in the reference letters for the corresponding points?
Thanks.
I would just define some configuration properties for your new plugin and use one of those properties to define where the point reference should be located and what the reference value should be.
Here is an example of what I mean. This would be in the chart's options property.
pointReferenceLetters: {
display: true,
fontColor: 'green',
references: [
{datasetIndex: 0, dataIndex: 1, reference: 'A'},
{datasetIndex: 1, dataIndex: 2, reference: 'B'},
]
}
The plugin would then use this data to draw the point references. Here is an example showing how a plugin would use this data. Note, I just did a quick implementation to show the concept, this plugin does not draw the reference circle like yours would.
Chart.plugins.register({
afterDraw: function(chartInstance) {
if (chartInstance.config.options.pointReferenceLetters || chartInstance.config.options.pointReferenceLetters.display) {
var references = chartInstance.config.options.pointReferenceLetters.references || [];
var helpers = Chart.helpers;
var ctx = chartInstance.chart.ctx;
var fontColor = helpers.getValueOrDefault(chartInstance.config.options.pointReferenceLetters.fontColor, chartInstance.config.options.defaultFontColor);
// render the value of the chart above the bar
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize + 5, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = fontColor;
chartInstance.data.datasets.forEach(function (dataset, dsindex) {
for (var i = 0; i < dataset.data.length; i++) {
// note, many browsers don't support the array.find() function.
// if you use this then be sure to provide a pollyfill
var refPoint = references.find(function(e) {
return e.datasetIndex == dsindex && e.dataIndex === i
});
if (refPoint) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
ctx.fillText(refPoint.reference, model.x, model.y + 30);
}
}
});
}
}
});
As you an see, the plugin uses the data provided in the pointReferenceLetters.references property to determine when a point reference should be drawn and then uses the values provided as the reference text.
Here is a codepen example that demonstrates all of this.
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.
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);
};
I've just moved to Famo.us and think it has some amazing potential. I am trying to build a new App using Famo.us and will be having 'layered' Views, one of which has a CanvasSurface inside.
My question is about how I would populate the CanvasSurface? I have checked the Docs and while they talk about some of the parameter options they do not tell you how.
I have a View within which I add a Layout and then a Surface to that Layout. Other Views that have ImageSurfaces work fine - but I do not know if I am on the right track with CanvasSurface.
So far I have: (part of inside a BackgroundView.js file)
function BackgroundView() {
View.apply(this, arguments);
_createLayout.call(this);
_createBody.call(this);
_setListeners.call(this);
}
function _createBody() {
this.bodySurface = new CanvasSurface({
canvasSize : [undefined, undefined]
});
var bodyContext= this.bodySurface.getContext('2d');
bodyContext.fillText("Text on Canvas", 100, 100);
this.layout.content.add(this.bodySurface);
}
It runs with no errors, but shows nothing. The CanvasSurface is rendered...
Are there any examples using CanvasSurface or does anyone have any thoughts?
Thanks again for your help in advance.
:)
There are a couple of things I added to your code.. Defining the prototype and prototype.constructor, as well as adding the CanvasSurface to the BackgroundView. I found that canvasSize does not currently support the undefined size attribute like Surface does. You need to be explicit and use pixel size.
Check out what I did to your code.. Hope this helps..
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var View = require('famous/core/View');
var CanvasSurface = require('famous/surfaces/CanvasSurface');
var context = Engine.createContext();
function BackgroundView() {
View.apply(this, arguments);
// _createLayout.call(this);
_createBody.call(this);
// _setListeners.call(this);
}
BackgroundView.prototype = Object.create(View.prototype);
BackgroundView.prototype.constructor = BackgroundView;
function _createBody() {
this.bodySurface = new CanvasSurface({
size:[400,200]
});
var bodyContext= this.bodySurface.getContext('2d');
bodyContext.font="20px Georgia";
bodyContext.fillText("Hello World!",50,50);
this.add(this.bodySurface);
}
var bg = new BackgroundView();
context.add(bg);
var circle = paper.getById(data.Id);
console.log("circle : " + circle);
circle.attr({ opacity: data.Opacity / 100 });
console output:
circle : Raphaël’s object
and
Uncaught TypeError: Cannot call method 'attr' of null
I think, first I convert object to circle? How can I change element attribute?
Thanks...
Its not really clear what your data object is, to know if thats correct, or if the id has been set. Here is an example.. with a fiddle here http://jsfiddle.net/Uvcy9/2/
var paper = Raphael('container',200,200);
var newCircle = paper.circle(100,20,20);
newCircle.id='circle1';
paper.add( newCircle );
/// some code here, later we want to reference it...
var circle = paper.getById('circle1');
circle.attr({ fill: 'red', opacity: circle.attr('opacity') / 10 });