Is it possible to animate the different parts of the transform property independently in one animation?
for example:
const lineAnimation = [
{ transform: 'scaleX(0)', offset: 0 },
{ transform: 'translateX(0%)', offset: 0 },
{ transform: 'translateX(0%)', offset: .25 },
{ transform: 'scaleX(1)', offset: .5 },
{ transform: 'translateX(100%)', offset: 1 },
]
// Timing object also defined...
loadLine1.animate(
lineAnimation,
loadLine1Timing
);
I would like to animate scaling and translation in the same animation for the same element but at different timings.
This particular example isn't working and seems to only be affecting the translateX and not the scale.
How could I modify this to transform both at once?
Unfortunately this is not yet possible. You need to create an extra wrapper around your loadLine1 element (e.g. if it is an SVG element, a <g> element, or if it is HTML, a <div> or <span> element), then you need to animate scale on loadLine1 and translate on the wrapper, or vice-versa depending on the desired effect.
Alternatively, you could write something like:
const lineAnimation = [
{ transform: 'scaleX(0) translateX(0%)', offset: 0 },
{ transform: 'scaleX(0.5) translateX(0%)', offset: .25 },
{ transform: 'scaleX(1) translateX(33%)', offset: .5 },
{ transform: 'scaleX(1) translateX(100%)', offset: 1 },
]
loadLine1.animate(
lineAnimation,
loadLine1Timing
);
(You might want to reverse the order of the scaleX() and translateX() components depending on the desired effect.)
In future this will be possible via two further means.
Firstly, CSS Transforms Level 2 specifies individual properties for translate and scale. This is implemented in Chrome but only behind a flag. I expect it will be implemented in Firefox in the near future.
This would allow you to write your animation as:
const lineAnimation = [
{ scale: 0, offset: 0 },
{ translate: '0%', offset: 0 },
{ translate: '0%', offset: .25 },
{ scale: 1, offset: .5 },
{ translate: '100%', offset: 1 },
]
loadLine1.animate(
lineAnimation,
loadLine1Timing
);
Secondly, Web Animations defines additive animation which would allow you to achieve this as follows:
const scaleAnimation = [
{ transform: 'scaleX(0)', offset: 0 },
{ transform: 'scaleX(1)', offset: .5 },
];
const translateAnimation = [
{ transform: 'translateX(0%)', offset: 0 },
{ transform: 'translateX(0%)', offset: .25 },
{ transform: 'translateX(100%)', offset: 1 },
];
loadLine1.animate(
scaleAnimation,
loadLine1Timing
);
loadLine1.animate(
translateAnimation,
{ ...loadLine1Timing, composite: 'add' }
);
This is implemented in Firefox but only enabled in Nightly builds. It is also implemented in Chrome, I believe, but only enabled behind the experimental web platform features flag. I hope this will ship in both browsers and the polyfill in early 2018.
Related
I want to have an animation where the nodes get colored then the edges get colored. I looked at the other questions regarding animation in cytoscape.js and tried stacking promise statements to no avail.
I'm also unclear as to what it is the queue does, setting the boolean for both the edge and node to true, false or staggered seems to have no difference on the animation as they both animate at the same time.
This is the code I have so far:
var a = cy.edges().animate({
position: { x: 100, y: 100 },
style: { lineColor: '#a79' }}, {duration: 1000},
{queue: 1}
);
var b = cy.nodes().animate({
position: { x: 100, y: 100 },
style: { backgroundColor: 'blue' }},
{duration: 1000},
{queue: 1}
);
a.animation().play().promise().then(b.animation().play());
edit
So I wrapped the animate command in a function to get the desired result
cy.on('tap', 'node', function(evt){
cy.nodes().animate(
{
position: { x: 100, y: 100 },
style: { lineColor: 'pink' }
},
{
duration: 1000,
queue: true
}
);
Although hardcoding animations is not ideal, I would still like to know how to do it with the promise commands.
It looks ok, the only thing I see is:
var a = cy.edges().animate(
{
position: { x: 100, y: 100 },
style: { lineColor: '#a79' }
},
{
duration: 1000,
queue: true
}
);
var b = cy.nodes().animate(
{
position: { x: 100, y: 100 },
style: { backgroundColor: 'blue' }
},
{
duration: 1000, // This goes together in one brace
queue: true // Use a boolean maybe
}
);
a.animation().play().promise().then(function () {
b.animation().play());
}
The documentation does exactly that, maybe this solves the problem :)
Bottom of highcharts rendered chart in pdf
I am attempting to render a highcharts chart inside a blade template and then pass the resulting view/html to DocRaptor in order to turn it into a pdf. The view is rendered with Laravel's View::make and then the render() function. Everything is working as expected except the rendered bars do not match up to the tick marks on the yAxis (horizontal).
I've included an image of what I'm referring to. In the image 2 of the bars (Saturn and Lexus) should be past the 1M tick and I would expect Acura to be further right towards the 1M tick mark. The image only contains the last 3 bars in the graph, but the same holds true for the series as whole.
Less relevent is that I've essentially split up the series data into small enough chunks such that the chart would fit on a page (hence the jQuery $.each()).
The code that produces the chart is below. The code inside the load and render functions are both executed as the document.write debug statements. Any help/ideas would be appreciated.
$("div[id^='Chart_chunk_count_']").each(function() {
var myChart = Highcharts.chart($(this).attr("id"), {
chart: {
borderWidth: 0,
events: {
load: function(event) {
document.write('In load event');
},
render: function(event) {
document.write('In render event');
}
},
height: j_audience_chart_chunks['metadata']['page'][$(this).data("chart-page")]['height'],
type: 'bar',
width: 650
},
credits: {
enabled: false
},
legend: {
enabled: false
},
plotOptions: {
bar: {
borderRadius: 3,
borderWidth: 0,
color: j_audience_chart_chunks['metadata']['count_chart']['color'],
pointWidth: 30,
turboThreshold: 0
},
series: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
/* allowOverlap: true, */
/* backgroundColor: '#FA9005', */
color: '#606060',
crop: false,
defer: false,
enabled: true,
format: '{point.y:,.0f}',
inside: true,
/* overflow: 'none', */
style: {
fontSize: "11px",
fontWeight: "normal",
textOutline: 'none'
}
}
}
},
title: {
text: (type == "index") ? "Index Against Profiled Audience" : "Audience Count"
},
tooltip: {
enabled: false
},
xAxis: {
categories: j_audience_chart_chunks['audience_data'][$(this).data("chart-page")]['categories'],
minorTickInterval: null,
title: {
text: null
}
},
yAxis: {
min: (type == 'count') ? 0 : -100,
max: j_audience_chart_chunks['metadata']['count_chart']['max'],
title: {
text: null
},
labels: {
/* format: '{point.y:,.0f}', */
overflow: 'justify'
/*
style: {
color: '#fa9005'
}
*/
}
},
series: j_audience_chart_chunks['audience_data'][$(this).data("chart-page")]['series']
});
});
What's happening is that the JavaScript finishes and DocRaptor/Prince begins building the PDF, but the default Highcharts animations haven't finished running. Disabling animations chart wide fixes this.
You need set chart.animation to false like:
chart: {
animation: false
}
I must remove the elements for the axis because I don't want to have empty space. I have to fit the graph in a panel.
I'm trying something like:
d3.select("g.c3-axis .c3-axis-y").remove();
d3.select("g.c3-axis-x").remove();
I printed this following selection in my console and it's all right but the remove doesn't work:
d3.select("svg").select(".c3-axis-x").selectAll("*").remove();
No results! What's the mistake ? I think that when I launch the function the chart is not completely generated, but I can't find a good solution to achieve the style desiderated.
I achieved the result in a different way, I fixed the padding for the axis in the chart.
axis:
{
x:
{
type: 'timeseries',
tick:
{
format : "%d-%m-%y"
},
show: false,
padding :
{
bottom : 0,
left: 0,
right: 0
}
},
y:
{
min: 0,
padding :
{
bottom : 0,
left: 0,
right: 0
},
tick:
{
values: [[0], [maxs]],
format: function (d) { return d3.format(',f')(d) +' kWh/h' }
},
show: false
}
},
I am using joint.js to generate a services flowchart. And I use the below code snippet to create my custom element.
// Create a custom element.
// ------------------------
joint.shapes.custom = {};
// The following custom shape creates a link out of the whole element.
joint.shapes.custom.ElementLink = joint.shapes.basic.Rect.extend({
// Note the `<a>` SVG element surrounding the rest of the markup.
markup: '<a><g class="rotatable"><g class="scalable"><rect/></g><text/></g></a>',
defaults: joint.util.deepSupplement({
type: 'custom.ElementLink'
}, joint.shapes.basic.Rect.prototype.defaults)
});
// Create JointJS elements and add them to the graph as usual.
// -----------------------------------------------------------
var supply = new joint.shapes.custom.ElementLink({
position: { x: 200, y: 110 }, size: { width: 250, height: 60 },
attrs: {
rect: { fill: '#3366ff', stroke: '#1d3d9e', 'stroke-width': 5 },
a: { 'xlink:href': 'http://www.aamrofreight.net/supply-chain-management/', cursor: 'pointer' },
text: { text: 'Supply Chain \nManagement', fill: 'white' }
}
});
Problem is that on a single left click on the supply element, the hyperlink does not open. Only when I drag and and release the element, the link opens in a new tab. Kindly suggest me what can be done to overcome this issue. I have disabled user dragging of elements using the
var paper = new joint.dia.Paper({ el: $('#paper'), width: 1040, height: 1000, gridSize: 1, model: graph, interactive: false });
Thanks in advance!
Here is your answer...
you didn't add xlink:show': 'new'. That's why it's not getting open.
create custom shap...
joint.shapes.custom = {};
joint.shapes.custom.ElementLink = joint.shapes.basic.Rect.extend({
// Note the `<a>` SVG element surrounding the rest of the markup.
markup: '<a><g class="rotatable"><g class="scalable"><rect/></g><text/></g></a>',
defaults: joint.util.deepSupplement({
type: 'custom.ElementLink'
}, joint.shapes.basic.Rect.prototype.defaults)
});
You Data:
var supply = new joint.shapes.custom.ElementLink({
position: { x: 200, y: 110 }, size: { width: 250, height: 60 },
attrs: {
rect: { fill: '#3366ff', stroke: '#1d3d9e', 'stroke-width': 5 },
a: { 'xlink:href': 'http://www.aamrofreight.net/supply-chain-management/', 'xlink:show': 'new', cursor: 'pointer' },
text: { text: 'Supply Chain \nManagement', fill: 'white' }
}
For more information..check here:
[http://jointjs.com/tutorial/hyperlinks
I hope, it should work for you.
I would like to show 3 color zones on my graph on the background according to y axis value, as I understand, I cannot control the background color by different colors.
My idea is to draw 3 horizontal lines with canvasOverlay - that is working.
The problem is I want to place this lines behind my graph curve, now it seen on the front and it overlays my points line.
Can I change the property of z-index or the opacity?
Maybe some other ideas?
$.jqplot( 'ChartDIV', [data],
{
series: [{ showMarker: true}],
highlighter: {
sizeAdjust: 10,
show: true,
tooltipLocation: 'n',
useAxesFormatters: true
},
tickOptions: {
formatString: '%d'
},
canvasOverlay: {
show: true,
objects: [
{
horizontalLine:
{
name: 'low',
y: 1.0,
lineWidth: 100,
color: 'rgb(255, 0, 0)',
shadow: false
}
},
{
horizontalLine:
{
name: 'medium',
y: 2.0,
lineWidth: 100,
color: 'rgb(250, 250, 0)',
shadow: true
}
},
{
horizontalLine:
{
name: 'high',
y: 3.0,
lineWidth: 100,
color: 'rgb(145, 213, 67)',
shadow: false
}
},
]
},
axes: {
xaxis:
{
label: 'Dates',
renderer: $.jqplot.DateAxisRenderer,
rendererOptions: { tickRenderer: $.jqplot.CanvasAxisTickRenderer },
tickOptions: {
formatString: '%d/%m/%Y',
angle: -30,
fontFamily: 'Arial',
fontSize: '13px',
fontWeight: 'bold'
},
min: d[0] + "/" + d[1] + "/01",
tickInterval: '2 month',
labelOptions: {
fontFamily: 'Arial',
fontSize: '14pt',
fontWeight: 'bold',
textColor: '#0070A3'
}
},
yaxis:
{
label: 'Level',
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
tickOptions: {
formatter: $.jqplot.tickNumberFormatter
},
rendererOptions: { tickRenderer: $.jqplot.CanvasAxisTickRenderer },
labelOptions: {
fontFamily: 'Arial',
fontSize: '14pt',
fontWeight: 'bold',
textColor: '#0070A3',
angle: -90
}
}
}
} );
I think that your problem might be the order in which you do your painting. I think that you first create the graph and then in it you draw this line, right?
Thus to sort out this you might try one of the hooks the jqPlot chart provides.
To see how you could use a hook, please see my other answer (BTW to my own question:) where I used a postDrawHooks hook to change format of labels once the graph is drawn. In your case you could use preDrawHooks or maybe more appropriate would be to use preDrawSeriesHooks, since I am not sure if a canvas is ready to use when function passed in preDrawHooks is called.
Remember that, according to the documentation, the preDrawSeriesHooks is called each time before a series is drawn, thus in your case you would need it to work just once.
EDIT
In this case the answer is simple, well you could do both, which is shown in my jsfiddle, available here.
You need this piece of code to send overlay canvas to back, which you should place before the code painting your graph:
$.jqplot.postDrawHooks.push(function(){
$(".jqplot-overlayCanvas-canvas").css('z-index', '0');//send overlay canvas to back
$(".jqplot-series-canvas").css('z-index', '1');//send series canvas to front
});
But when it comes to opacity you could apply it to whichever line you like (also shown in my code), using of the rgba() method, for series it is done this way:
seriesColors:['rgba(100, 150, 100, 0.75)']
for the lines on canvas, you do it like this:
color: 'rgba(145, 213, 67, 0.25)'
EDIT2
The most important think was forgotten therefore with the previous code the highlighter was not working. Simply the event canvas which is responsible for event catching and propagation was hidden underneath our canvas. It was corrected in the current version of code, by setting of an appropriate z-index for it. The complete method would look like:
$.jqplot.postDrawHooks.push(function() {
$(".jqplot-overlayCanvas-canvas").css('z-index', '0'); //send overlay canvas to back
$(".jqplot-series-canvas").css('z-index', '1'); //send series canvas to front
$(".jqplot-highlighter-tooltip").css('z-index', '2'); //make sure the tooltip is over the series
$(".jqplot-event-canvas").css('z-index', '5'); //must be on the very top since it is responsible for event catching and propagation
});
EDIT3:
A much nicer solution where we do not need to worry about setting the z-index.
$.jqplot.postDrawHooks.push(function() {
var overlayCanvas = $($('.jqplot-overlayCanvas-canvas')[0])
var seriesCanvas = $($('.jqplot-series-canvas')[0])
seriesCanvas.detach();
overlayCanvas.after(seriesCanvas);
});
It is presented here. This solution is inspired by the answer provided by #Mark to a similar sort of problem.
A much better solution is to use Canvas rectangle object without any hacking
http://services.mbi.ucla.edu/jqplot/examples/draw-rectangles.html
$(document).ready(function(){
var plot1 = $.jqplot ('chart1', [[30,-10,90,20,50,130,80,120,50]], {
canvasOverlay: {
show: true,
objects: [
{ rectangle: { ymax: 0, xminOffset: "0px", xmaxOffset: "0px", yminOffset: "0px", ymaxOffset: "0px",
color: "rgba(0, 0, 200, 0.3)", showTooltip: true, tooltipFormatString: "Too Cold" } },
{ rectangle: { ymin: 100, xminOffset: "0px", xmaxOffset: "0px", yminOffset: "0px", ymaxOffset: "0px",
color: "rgba(200, 0, 0, 0.3)", showTooltip: true, tooltipFormatString: "Too Warm" } }
]
}
});
});