JQPlot replot. Updating PointLabels - jqplot

I have a bar chart and I need to update its data, also a PointLabels. Data is updating, but PointLabels are the same, from previous plot. How to update a PointLabels?
// here are labels.
var my_labels = [["2 g. <br /> 47$"],["2 g. <br /> 48$"],["7 g. <br /> 49$"],[],["10 g. <br /> 51$"],["6 g. <br /> 52$"],["4 g. <br /> 53$"]];
$.jqplot.config.enablePlugins = true;
var s1 = [2, 6, 7, '' , 10, 6, 4];
var ticks = [47,48, 49, 50, 51, 52, 53];
// initializing plot
plot1 = $.jqplot('chart1', [s1], {
// Only animate if we're not using excanvas (not in IE 7 or IE 8)..
canvasOverlay: {
show: true,
objects: [
{verticalLine: {
name: 'barney',
x: 4,
lineWidth: 2,
color: 'gray',
shadow: false
}}
]
},
animate: !$.jqplot.use_excanvas,
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
// setting labels to my own defined labels
pointLabels: { show: true, labels : my_labels, escapeHTML: false },
color: '#E6D49F'
},
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks,
max: 100
}
},
highlighter: { show: false },
});
$('#chart1').bind('jqplotDataClick',
function (ev, seriesIndex, pointIndex, data) {
$('#info1').html('series: '+seriesIndex+', point: '+pointIndex+', data: '+data);
}
);
});
// reploting function call
setInterval(function(){replot()},4000);
var a = 1;
var labels;
// reploting function
function replot()
{
var data;
switch(a)
{
case 1:
data = [[1,4], [2,6], [3, 8],[4,0],[5, 9],[6, 7],[7, 3]];
labels = [["4 g. <br /> 47$"],["6 g. <br /> 48$"],["8 g. <br /> 49$"],[],["9 g. <br /> 51$"],["7 g. <br /> 52$"],["3 g. <br /> 53$"]];
break;
case 2:
data = [[1,3], [2,7], [3, 7],[4,0],[5, 8],[6, 6],[7, 4]];
labels = [["3 g. <br /> 47$"],["6 g. <br /> 48$"],["8 g. <br /> 49$"],[],["9 g. <br /> 51$"],["7 g. <br /> 52$"],["3 g. <br /> 53$"]];
break;
case 3:
data = [[1,5], [2,5], [3, 9],[4,0],[5, 10],[6, 8],[7, 2]];
labels = [["5 g. <br /> 47$"],["6 g. <br /> 48$"],["8 g. <br /> 49$"],[],["9 g. <br /> 51$"],["7 g. <br /> 52$"],["3 g. <br /> 53$"]];
break;
}
//updating data
plot1.series[0].data = data;
//trying to update pointlabels
plot1.series[0].pointLabels.labels = labels;
plot1.replot();
if(a == 3)
a = 0;
a++;
}

I had the same problem and thought that I am doing something wrong. But now seeing someone else with the same problem, it seems that the problem is with the plugin itself.
I found a workaround to this problem from one of the comments on my own post.
After replot try directly updating the divs containig the point labels like this.
for(i=0;i<labels.length;i++){
$("#chart1").find('.jqplot-series-0.jqplot-point-'+i).html(''+labels[i]);
}
I hope someone will provide a better solutions someday instead of this workaround.

I appreciate this is an old thread but I have just experienced the same issue and added the following as the first line in the "$.jqplot.PointLabels.draw" function, which removes all previously added labels prior to re-drawing them:
$('.jqplot-point-label',plot.target).remove();

Ran into a similar problem and found this answer. Updating plot1.series[0].plugins.pointLabels.labels instead of plot1.series[0].pointLabels.labels did the trick for me.

Related

Highcharts Animation

Is there anyway to animate each and every bubble in bubble charts one by one, from left to right and the size of the bubbles will initially be either smaller or larger and then it should grow to the actual size. Any ideas to proceed further with this requirement is highly appreciated.
/**
* A Highcharts plugin to display the tooltip in a separate container outside the chart's
* bounding box, so that it can utilize all space available in the page.
*/
(function(H) {
H.wrap(H.Tooltip.prototype, 'getLabel', function(proceed) {
var chart = this.chart,
options = this.options,
chartRenderer = chart.renderer,
box;
if (!this.label) {
this.renderer = new H.Renderer(document.body, 400, 500);
box = this.renderer.boxWrapper;
box.css({
position: 'absolute',
top: '-9999px'
});
chart.renderer = this.renderer;
proceed.call(this, chart, options);
chart.renderer = chartRenderer;
this.label.attr({
x: 0,
y: 0
});
this.label.xSetter = function(value) {
box.element.style.left = value + 'px';
};
this.label.ySetter = function(value) {
box.element.style.top = value + 'px';
};
}
return this.label;
});
H.wrap(H.Tooltip.prototype, 'getPosition', function(proceed, boxWidth, boxHeight, point) {
var chart = this.chart,
chartWidth = chart.chartWidth,
chartHeight = chart.chartHeight,
pos;
point.plotX += this.chart.pointer.chartPosition.left;
point.plotY += this.chart.pointer.chartPosition.top;
// Temporary set the chart size to the full document, so that the tooltip positioner picks it up
chart.chartWidth = $(document).width();
chart.chartHeight = $(document).height();
// Compute the tooltip position
pos = proceed.call(this, boxWidth, boxHeight, point);
// Reset chart size
chart.chartWidth = chartWidth;
chart.chartHeight = chartHeight;
return pos;
});
/**
* Find the new position and perform the move. This override is identical
* to the core function, except the anchorX and anchorY arguments to move().
*/
H.Tooltip.prototype.updatePosition = function(point) {
var chart = this.chart,
label = this.label,
pos = (this.options.positioner || this.getPosition).call(
this,
label.width,
label.height,
point
);
// do the move
this.move(
Math.round(pos.x),
Math.round(pos.y || 0), // can be undefined (#3977)
point.plotX + chart.plotLeft - pos.x,
point.plotY + chart.plotTop - pos.y
);
};
}(Highcharts));
var chart = new Highcharts.Chart({
chart: {
height: 500,
renderTo: 'container',
type: 'pie'
},
tooltip: {
formatter: function() {
return '<div class="MyChartTooltip">test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> test<br /> </div>';
}
},
series: [{
data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
}]
});
You can add point with small z values and then update them one by one asynchronously (after the one point is updated, update the next one)
You can also override bubble.prototype.animate function and change default animation-like this:
Highcharts.seriesTypes.bubble.prototype.animate = function(init) {
var H = Highcharts
var each = H.each
var animation = this.options.animation;
var points = this.points
var animatePoint = i => {
var point = points[i]
var graphic = point && point.graphic
var animationTarget
if (graphic && graphic.width) {
animationTarget = {
x: graphic.targetX,
y: graphic.targetY,
width: graphic.targetWidth,
height: graphic.targetHeight
}
graphic.animate(animationTarget, animation, () => {
animatePoint(i + 1)
});
} else {
this.update({ dataLabels: { enabled: true }})
}
}
if (!init) { // run the animation
each(points, function(point) {
var graphic = point.graphic,
animationTarget;
if (graphic && graphic.width) { // URL symbols don't have width
graphic.targetWidth = graphic.width
graphic.targetHeight = graphic.height
graphic.targetX = graphic.x
graphic.targetY = graphic.y
// Start values
graphic.attr({
x: point.plotX,
y: point.plotY,
width: 1,
height: 1
});
}
});
animatePoint(0)
// delete this function to allow it only once
this.animate = null;
}
}
example: http://jsfiddle.net/hpk497hb/

svg manipulation app - record and play svg manipulations [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm looking to build a moble app where the user can take an SVG image, manipulate it under a "recording", and then send the recording to a friend for them to "replay".
I have some experience with D3.js and have also looked at Snap.svg library for SVG manipulation but I'm not fully wrapping my head around how to implement this.
In particular, what's a good way to be able to save the manipulations the user is making and then "replay" them? For example, I can use D3.js to manipulate the SVG, but since this is code-based, I can't exactly "serialize" the animation in order to send to someone else and for them to be able to "replay" it. I don't want to go down the route of code generation..
Any ideas how to do this?
I am not sure how complex your application targets are. However, it is easy to serialise updates in an SVG as JSON array and replay them using d3. Here is a small example for the same.
Steps:
Update SVG by using update buttons.
Revert the chart by clicking on clear button.
Now click play button to replay the last updates.
var defaults = [{
key: "r",
val: 15,
type: "attr"
}, {
key: "fill",
val: "blue",
type: "style"
}];
var updates = [];
var c20 = d3.scale.category20();
var circles = d3.selectAll("circle");
d3.select("#increase_rad")
.on("click", function() {
var val = parseInt(d3.select("circle").attr("r")) + 1;
circles.attr("r", val);
updates.push({
"key": "r",
"val": val,
"type": "attr"
});
enableButton();
});
d3.select("#decrease_rad")
.on("click", function() {
var val = parseInt(d3.select("circle").attr("r")) - 1;
circles.attr("r", val);
updates.push({
"key": "r",
"val": val,
"type": "attr"
});
enableButton();
});
d3.select("#change_color")
.on("click", function() {
var val = c20(Math.floor(Math.random() * (18) + 1));
circles.style("fill", val);
updates.push({
"key": "fill",
"val": val,
"type": "style"
});
enableButton();
});
d3.select("#clear")
.on("click", function() {
applyEffects(defaults);
});
d3.select("#play")
.on("click", function() {
applyEffects(updates);
});
function applyEffects(effects, delay) {
var trans = circles.transition()
effects.forEach(function(update) {
if (update.type == "attr") {
trans = trans.attr(update.key, update.val).transition();
} else {
trans = trans.style(update.key, update.val).transition();
}
});
}
function enableButton() {
d3.select("#clear").attr("disabled", null);
d3.select("#play").attr("disabled", null);
}
svg {
background: white;
}
.link {
stroke: black;
}
.node {
fill: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div>
<input type="button" value="Clear" id="clear" disabled />
<input type="button" value="Play" id="play" disabled />
<br/>
<br/>
<input type="button" value="Increase Radius" id="increase_rad" />
<input type="button" value="Decrease Radius" id="decrease_rad" />
<input type="button" value="Change Color" id="change_color" />
</div>
<svg width="250" height="250">
<g id="links">
<line class="link" x1="138.0538594815113" y1="55.927846328346924" x2="58.77306466322782" y2="110.43892621419347"></line>
<line class="link" x1="138.0538594815113" y1="55.927846328346924" x2="195.04044384802015" y2="133.44259356292176"></line>
</g>
<g id="nodes">
<g class="node" transform="translate(138.0538594815113,55.927846328346924)">
<circle r=15></circle>
</g>
<g class="node" transform="translate(58.77306466322782,110.43892621419347)">
<circle r=15></circle>
</g>
<g class="node" transform="translate(195.04044384802015,133.44259356292176)">
<circle r=15></circle>
</g>
</g>
</svg>

kendo ui using slider with a template

I'm using a slider inside of Kendo UI Template.
<script type="text/x-kendo-template" id="template3">
<div>
<b> Grades: </b> <br />
<input id="slider" class="temperature" value="#= temper #" data-bind="value:temper"/>
</div>
</script>
The template is called by edit function on the grid.
var grid = $("#grid").kendoGrid({
editable: {
mode:"popup",
template:kendo.template($("#template3").html())
},
...
I created the JS slider
var slider = $("#slider").kendoSlider({
increaseButtonTitle: "Right",
decreaseButtonTitle: "Left",
min: 0,
max: 5,
smallStep: 1,
largeStep: 2
}).data("kendoSlider");
The problem is that the Slider is not displayed on the popup editor. Only is displayed the value. Could anybody please help me?
Your slider element isn't initially available thus $("#slider") returns nothing. You should call this code once the grid initializes its editor template. Use the edit event of the grid for that:
var grid = $("#grid").kendoGrid({
editable: {
mode:"popup",
template:kendo.template($("#template3").html())
},
edit: function() {
$("#slider").kendoSlider({
increaseButtonTitle: "Right",
decreaseButtonTitle: "Left",
min: 0,
max: 5,
smallStep: 1,
largeStep: 2
})
}
Alternatively you can set the data-role attribute:
<script type="text/x-kendo-template" id="template3">
<div>
<b> Grades: </b> <br />
<input data-role="slider"
data-min="0"
data-max="0"
data-small-step="1"
data-large-step="2"
class="temperature"
data-bind="value:temper"
/>
</div>
</script>

Persisting the default value of the numeric text after deleting entered value

Have a look at the sample here.
The problem I have is that I need to have 0.00 value remain in the numerictextbox even though the value is deleted in the control. At the moment it appears as empty on the UI. Can anyone advise the cleanest solutions for problem?
You can achieve your goal wiring the change event of the widget and modify its value and the model's one when it is triggered.
<div id="view">
<div data-template="containertpl" data-bind="source: People"></div>
<button data-bind="click: AddNew">Add</button>
</div>
<script id="containertpl" type="text/x-kendo-template">
<div>
<label for="FirstName#:id#">Name</label>
<input name="FirstName#:id#" type="text" data-bind="value: FirstName"/>
<input data-role="numerictextbox" data-bind="value: Income, events: { change: numericChange }"/>
</div>
</script>
var viewModel = kendo.observable({
People: [
{id: 1, FirstName: "", Income: "0.00" },
{id: 2, FirstName: "", Income: "0.00" },
{id: 3, FirstName: "", Income: "0.00" }
],
numericChange: function(args) {
var numeric = args.sender;
if (numeric.value() === null) {
numeric.value(0);
args.data.set("Income", 0);
}
}
});
viewModel.AddNew = function(){
viewModel.People.push({id: viewModel.People.length + 1, FirstName: "Generated", Income: "0.00"});
};
$(document).ready(function(){
kendo.bind($("#view"), viewModel);
});

Scriptaculous slider price range slider with two handle

I'm using Scriptaculous to create a price range slider with two handles says minimum and maximum values. How can I store minimum and maximum values in separate hidden field.
Current script as follows,
<div id="price-range" class="filter-track">
<span id="price-min" class="filter-handle" title="Scroll to set your minimum value">>></span>
<span id="price-max" class="filter-handle" title="Scroll to set your maximum value"><<</span>
</div>
<input type="hidden" name="price" id="beds" value="0,100"/>
var loadPriceSlider = function () {
var handles = [$('price-min'), $('price-max')];
// horizontal slider control with preset values
new Control.Slider(handles, 'price-range', {
range:$R(0, 5000, false),
sliderValue: [0, 3000],
values: [0, 100, 200, 300],
restricted: true,
onChange: function(v){
$('price').value = v;
}
});
};
It will store comma separated (min,max) values in price field. but i would like to store this in separate field. How to do this? Any help please?
Your code tries to refer to $('price') but you the input with the name 'price' has the 'id' of 'beds'.
Here's corrected HTML which has the price field, and an additional field:
<div id="price-range" class="filter-track">
<span id="price-min" class="filter-handle"
title="Scroll to set your minimum value">>></span>
<span id="price-max" class="filter-handle"
title="Scroll to set your maximum value"><<</span>
</div>
<ul>
<li>price: <input type="text" name="price" id="price" value="0,100"/></li>
<li>myRange <input type="text" name="myRange" id="myRange" value="0,100"/></li>
</ul>
And the JavaScript:
var handles = [$('price-min'), $('price-max')];
// horizontal slider control with preset values
new Control.Slider(handles, 'price-range', {
range: $R(0, 5000, false),
sliderValue: [0, 3000],
values: [0, 100, 200, 300],
restricted: true,
onChange: function(val){
$('price').value = val;
$('myRange').value = val;
}
});
This works, loading these JavaScript:
<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/scriptaculous/1.9.0/scriptaculous.js?load=slider"></script>

Resources