Animation chart js (line), animate chart drawing line by line - javascript

Is there a way to extend the current chart.js so that the animation drawing doesn't animate the whole chart, but drawing the chart line by line with animation (ease) ?

You can use the onAnimationComplete callback to change the data and call update()
...
data: [0, 0, 0, 0, 0, 0, 0]
}
]
};
var data2 = [28, 48, 40, 19, 86, 27, 90];
var done = false;
var myLineChart = new Chart(ctx).Line(data, {
animationEasing: 'linear',
onAnimationComplete: function () {
if (!done) {
myLineChart.datasets[1].points.forEach(function (point, i) {
point.value = data2[i];
});
myLineChart.update();
done = true;
}
}
});
It works better with linear easing (otherwise it seems like 2 distinct animations), but if you wanted to, you could write your own easing function to do easeOutQuart in 2 blocks.
Fiddle - http://jsfiddle.net/rnyekq1y/

Nevermind.I've implement it by extending chart.js and override draw() function so that I can animate the line from one dot/point to another until the last dot / point.

Related

Phaser.js Implementing Minecraft lighting

So, I was looking into making minecraft/terraria block lighting
(like how some tiles are dark)
So far, I've seen the high level idea being
"set the sky block to the max light level, and reduce by x for every block, get light level by averaging light levels"
So my question is Mainly, How can I implement this in phaser? would I need to give every tile the value and calculate it?
There is an official example, that covers answers you question (if I undertand your question correct).
Here a slightly alter version of the example:
(it is a very crude example, to show case the idea)
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
scene: {
preload,
create
}
};
var game = new Phaser.Game(config);
function preload (){
this.load.image('tiles', 'https://labs.phaser.io/assets/tilemaps/tiles/catastrophi_tiles_16.png');
this.load.tilemapCSV('map', 'https://labs.phaser.io/assets/tilemaps/csv/catastrophi_level2.csv');
}
function create () {
this.add.text(10, 10, 'Click to change light position')
.setOrigin(0)
.setDepth(100)
.setStyle({fontFamily: 'Arial'});
let map = this.make.tilemap({ key: 'map', tileWidth: 16, tileHeight: 16 });
let tileset = map.addTilesetImage('tiles');
map.createLayer(0, tileset, 0, 0);
let lightSource = {x: 0, y: 0};
updateMap(map, lightSource);
this.input.on('pointerdown', (pointer) => updateMap(map, pointer));
}
function updateMap (map, lightSource) {
let fullLightDistanceInTiles = 3;
let origin = map.getTileAtWorldXY(lightSource.x, lightSource.y);
map.forEachTile(function (tile) {
var dist = Phaser.Math.Distance.Chebyshev(
origin.x,
origin.y,
tile.x,
tile.y
) - fullLightDistanceInTiles;
tile.setAlpha(1 - 0.1 * dist);
});
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
It basically just calculates the distance from the player to the tiles and set the alpha value. You would have to modify it so, that the distance is caluclate from a fixed sun/light position or so. (and recalculation would only be necessary if the sun/light position move)
if you don't want to set the alpha on the map tiles you could create a second layer with only black/grey tiles above, and set the alpha on this layer, but this would muddy the colors abit.
Alternatively, if: the light is horizontal and has the same level, you could simply overlay a gradient image or so. This would be better for performance and less work.
Here a demo using a phaser generated gradient:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
scene: {
preload,
create
}
};
var game = new Phaser.Game(config);
function preload (){
this.load.image('tiles', 'https://labs.phaser.io/assets/tilemaps/tiles/catastrophi_tiles_16.png');
this.load.tilemapCSV('map', 'https://labs.phaser.io/assets/tilemaps/csv/catastrophi_level2.csv');
}
function create () {
this.add.text(10, 10, 'fixed horizontal darkness')
.setOrigin(0)
.setDepth(100)
.setStyle({fontFamily: 'Arial'});
let map = this.make.tilemap({ key: 'map', tileWidth: 16, tileHeight: 16 });
let tileset = map.addTilesetImage('tiles');
map.createLayer(0, tileset, 0, 0);
var graphicsOverlay = this.add.graphics();
graphicsOverlay.fillGradientStyle(0x0, 0x0, 0x0, 0x0, 0,0,1,1);
graphicsOverlay.fillRect(0, config.height/3, config.width, config.height*2/3);
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>

Is there a way to calculate custom label position on a Highcharts Activity Gauge?

I have a Highcharts activity gauge that has two series. I am trying to place labels at the starting point of each ring. I have it working with hardcoded x,y coordinates, but I'm wondering if there is a way to calculate the location instead. It looks like this currently:
Here is the code I am using to add the labels in the chart render event:
function render() {
var chart = this;
chart.renderer.label('Completed 65%', 24, 25, 'rect', 0, 0, true, true, '')
.add();
chart.renderer.label('Follow-up 45%', 28, 42, 'rect', 0, 0, true, true, '')
.add();
}
I'd like to calculate the x,y values in the chart.renderer.label() function instead of hardcoding them to 24,25 and 28,42. However, I have not been able to find anything in the object model to locate the physical location of the series starting x and y, or the size of the label. I have many of these activity gauges to complete and going through them all and trying to find the magic coordinates seems like the wrong approach.
You can follow the same approach as icons rendered in the official Activity gauge demo here: https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/gauge-activity/
There you will find position calculated using series point shapeArgs. I modified that function to render labels as you expected. Check it in the demo posted below.
Function code:
function renderLabels() {
var offsetTop = 5,
offsetLeft = 5;
if (!this.series[0].label) {
this.series[0].label = this.renderer
.label('Completed 65%', 0, 0, 'rect', 0, 0, true, true)
.add(this.series[1].group);
}
this.series[0].label.translate(
this.chartWidth / 2 - this.series[0].label.width + offsetLeft,
this.plotHeight / 2 - this.series[0].points[0].shapeArgs.innerR -
(this.series[0].points[0].shapeArgs.r - this.series[0].points[0].shapeArgs.innerR) / 2 + offsetTop
);
if (!this.series[1].label) {
this.series[1].label = this.renderer
.label('Follow-up 45%', 0, 0, 'rect', 0, 0, true, true)
.add(this.series[1].group);
}
this.series[1].label.translate(
this.chartWidth / 2 - this.series[1].label.width + offsetLeft,
this.plotHeight / 2 - this.series[1].points[0].shapeArgs.innerR -
(this.series[1].points[0].shapeArgs.r - this.series[1].points[0].shapeArgs.innerR) / 2 + offsetTop
);
}
Function invocation:
chart: {
type: 'solidgauge',
events: {
render: renderLabels
}
}
Demo:
https://jsfiddle.net/BlackLabel/vpj32tmy/

leaflet - need to draw range radius semi circles

i need to draw a graph of semi circle on a leaflet map.
It should look like the following image:
How can i do it?
Thanks
Efrat
Have you seen leaflet-semicircle? Not exactly what you need, but might give you enough clues to implement what you want.
Did a quick example (demo here):
function rangerings (latlng, options) {
options = L.extend({
count: 8,
interval: 1000,
direction: 0,
spread: 120
}, options);
var layer = L.featureGroup();
for (var i = 1; i <= options.count; i++) {
L.semiCircle(latlng, {
radius: i * options.interval,
fill: false,
color: '#000',
weight: 1
}).setDirection(options.direction, options.spread).addTo(layer);
}
return layer;
}
code on github

Javascript Raphael problems with function in loop

Please bear with me, I'm still new to Javascript...
Here are two fiddles. The only difference between them is one has a text object as a title and the other does not; but this difference profoundly affects what happens when I mouseover the circle objects.
What I want is the behavior of the second fiddle, when there is a title like the first fiddle.
I've been trying to figure out how to get my function out of the loop so JSHint stops giving me an error... I have a feeling this behavior is caused by my lack of understanding of closure, binding, etc.
Fiddle 1 with title, mouseover is weird
Fiddle 2 no title, mouseover works
//Code for Fiddle 1: the only difference in Fiddle 2 is the indicated portion is commented out
var rsr = Raphael("holder", '1160', '1400');
// in the next fiddle this will be commented out
rsr.text(220, 50, 'Title').attr({
'font-size': 32,
'text-anchor': 'middle'
});
// end of comment out in Fiddle 2
var cir = []; // an array of circles
var xco = [206, 144.9, 317.4, 317.5]; // x coordinates of circle centers
var yco = [167.7, 231.8, 191.4, 256.8]; // y coordinates of circle centers
var rd = [25.5, 46, 34, 18.5]; // radii of circles
var circcolr = ['#939dac', '#000000', '#ecea5a', '#0da9f2']; // fill colors of circles
for (var i = 0; i < 4; i++) { // loop to draw circles
cir[i] = rsr.circle(xco[i], yco[i], rd[i]);
cir[i].attr({
fill: circcolr[i],
'fill-opacity': 1,
stroke: 'none'
});
}
for (var i in cir) {
(function (st) {
console.log(st.id);
st.node.onmouseover = function () {
st.animate({
r: rd[st.id] * 1.2
}, 200);
};
st.node.onmouseout = function () {
st.animate({
r: rd[st.id]
}, 100);
};
})(cir[i]);
}
The answer is pretty much there in the console logging you're already doing.
In the first case you create 5 objects the title and 4 circles so the title has id = 0 and the circles have id = 1, 2, 3, and 4.
In the second case you're only creating the circles so they have id = 0, 1, 2, 3
When you index into the rd array you're off by one in the title case. Changing the code at the end to this makes it work the same...
for (var i in cir) {
(function (cir, i) {
console.log(cir[i]);
cir[i].node.onmouseover = function () {
cir[i].animate({
r: rd[i] * 1.2
}, 200);
};
cir[i].node.onmouseout = function () {
cir[i].animate({
r: rd[i]
}, 100);
};
})(cir, i);
}

Create a gauge using jsgauge

I have created a gauge using jsgauge plugin
What I am not able to do is to control the speed of the needle. It should move to the assigned value a bit slower than the default speed. The needle should also start from 0.
The fiddle for this is http://jsfiddle.net/aryan7987/h45Tr/2/
Query(document).ready(function(){
jQuery("#example")
.gauge({
min: 0,
max: 100,
label: 'EMPLOYEE',
startangle: 0,
bands: [{color: "#ff0000", from: 90, to: 100}]
})
.gauge('setValue', 59);
});
One of solutions is to use setInterval function and increase gauge value step by step with needed delay like this:
jQuery(document).ready(function(){
var g = jQuery("#example")
.gauge({
min: 0,
max: 100,
label: 'RPM',
bands: [{color: "#ff0000", from: 90, to: 100}]
});
var m = 0;
var timer = window.setInterval(function()
{
m++;
g.gauge('setValue', m);
if (m==58)
{
clearInterval(timer);
}
}, 200);
});
The code is quite dirty but you should get a point. Also here working fiddle.
Unfortunately it looks like the speed is hardcoded by defining the delta for each frame. Here is an monkey patched version to change the speed see this jsfiddle
The problem line is:
increment = Math.max(Math.abs( that.settings.pointerValue - pointerValue ) / 8, 3);

Categories

Resources