Google Line Chart: drag to adjust value - javascript

I've recently dropped use of Graphael and and extensions package Ico. I think it's still a great library, it just needs better documentation and a proper API before it can be widely adopted.
I've converted the areas with charting to use Google Charts and can't seem to find a way to do one particular feature I used graphael for: drag support. One of my line charts needs to be editable, meaning that individual dots on the line can be dragged up and down to adjust value.
I've been trying to find an event or a way to attach an event in the API without much success. Has anyone managed to do something like that?
It's supposedly possible to do custom charts - would it be possible to do it this way?
EDIT: Seems like it's not really possible or is incredibly hard to hook into Google API or outputted SVG. It being in an iframe and no source code available just makes it less and less attractive option.
I've since started experimenting with Highcharts. I was able to do everything that Google engine does and can fiddle with chart after it's been rendered. Since source code is provided it makes it easier to figure certain things out. It also seems to work a bit faster than Google solution since it uses path when doing a Line Chart instead of individual SVG circle elements.
The issue I'm facing now has to do with the SVG Path element - there is no single point to set up drag on. So in order to use jQuery.draggable one has to inject a SVG Circle or another element at the same position as the SVG Path fragment tying to drag. So the following has to be resolved:
- how to place the created element to correct position?
- how to move element when chart is scaled (min or max value change on either axis)?
- how to convert new position back to a value, scaled for series data supplied?
Has anyone got enough in depth experience with Highcharts to fiddle with these? I'll try to provide JSfiddle example when possible.

Draggable points is not built-in into Highcharts but using the events and methods in the API it is possible to implement an editable line/column/scatter/area-chart (will only handle moving the point in y-direction so far). The following example uses mousemove, mousedown and mouseup events to handle interaction.
At mousedown the start y value is recorded if a point is focused. The y-axis.translate method is the key here, it will translate mouse position to the data domain.
At mousemove the focused point and tooltip is updated with the new value.
At mouseup the point is updated and a new event drop is fired that updates the text in a status message.
Full example on jsfiddle.
See also the feature request draggable points

This is now an available plugin on Highcharts:
http://www.highcharts.com/plugin-registry/single/3/Draggable%20Points

Realize this is a rather old question, yet its highly referenced in relation to Google Charts, so perhaps this will help someone.
Spent a while working on this exact same issue, and with the help of several answers from #WhiteHat finally managed to get this working.
Basically, you need to addEventListener to the container for the chart for "mousemove", "mouseup", and "mousedown" and then track whether you're currently selected on a point or dragging a point.
The rest mostly ends up being a lot of edge and distance and scaling calculations to try and figure out where the point actually is at in the chart.
The main parts that end up being really relevant are:
// Get layout object for the chart (mostly for bounding boxes)
var chartLayout = myLineChart.getChart().getChartLayoutInterface();
// Get the actual chart container (has all the chart properties as sub-variables)
var chartContainer = document.getElementById( myLineChart.getContainerId() );
// Find the outer (beyond title and axes labels) limits of chart
// Varies with screen scrolling
var chartBounds = chartContainer.getBoundingClientRect();
// Find the actual drawn region where your lines are (offset relative to chart)
var chartAreaBounds = chartLayout.getChartAreaBoundingBox();
Once you've actually figured out where the point is at with your mouse movement, then the location can be adjusted with:
var dataTable = myLineChart.getDataTable();
var spX = ( x - chartBounds.left - chartAreaBounds.left ) / chartAreaBounds.width * ( chartMaxX - chartMinX );
var spY = ( chartAreaBounds.height - ( y - chartBounds.top - chartAreaBounds.top ) ) / chartAreaBounds.height * ( chartMaxY - chartMinY );
dataTable.setValue( selectedPoint.row, 0, spX );
dataTable.setValue( selectedPoint.row, selectedPoint.column, spY );
A working example is included below that has two different line datasets with separate X values.
google.charts.load('current', {'packages':['corechart']});
google.charts.setOnLoadCallback( initChart );
var myLineChart;
var selectedPoint = null;
var arrData = [
['Age', 'Weight', 'Weight2'],
[ 3, 3.5, null ],
[ 4, 5, null ],
[ 4, 5.5, null ],
[ 6.5, 7, null ],
[ 8, 12, null ],
[ 11, 14, null ],
[ 1, null, 3.551 ],
[ 2, null, 12.753 ],
[ 3, null, 5.058 ],
[ 4, null, 6.620 ],
[ 5, null, 12.371 ],
[ 6, null, 1.342 ],
[ 7, null, 5.202 ],
[ 8, null, 7.008 ]
];
var data;
var options = {
title: 'Age vs. Weight comparison',
hAxis: {title: 'Age', minValue: 0, maxValue: 15},
vAxis: {title: 'Weight', minValue: 0, maxValue: 15},
legend: 'none'
};
function initChart(){
data = google.visualization.arrayToDataTable( arrData );
myLineChart = new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'exampleChart',
dataTable: data,
options: options
});
document.getElementById("exampleChart").addEventListener( "mousemove", mouseMoveScript );
document.getElementById("exampleChart").addEventListener( "mousedown", mouseDownScript );
document.getElementById("exampleChart").addEventListener( "mouseup", mouseUpScript );
drawChart();
}
function drawChart() {
myLineChart.draw();
}
function selectPoints( mx, my ) {
var chartLayout = myLineChart.getChart().getChartLayoutInterface();
var chartContainer = document.getElementById( myLineChart.getContainerId() );
var chartBounds = chartContainer.getBoundingClientRect();
if ( ( ( (chartBounds.left + window.pageXOffset) <= mx ) && ( (chartBounds.left + chartBounds.width + window.pageXOffset) >= mx ) ) &&
( ( (chartBounds.top + window.pageYOffset) <= my ) && ( (chartBounds.top + chartBounds.height + window.pageYOffset) >= my ) ) ){
var selection = [];
var dataTable = myLineChart.getDataTable();
for (var row = 0; row < dataTable.getNumberOfRows(); row++) {
for (var col = 1; col < dataTable.getNumberOfColumns(); col++) {
var point = chartLayout.getBoundingBox('point#' + (col - 1) + '#' + row);
if( point != null ){
if ((((chartBounds.left + point.left) >= (mx - point.width)) &&
((chartBounds.left + point.left + point.width) <= (mx + point.width))) &&
(((chartBounds.top + point.top) >= (my - point.height)) &&
((chartBounds.top + point.top + point.height) <= (my + point.height)))) {
selection.push({row: row, column: col});
}
}
}
}
if( selection.length > 0 ){
var item = selection[0];
selectedPoint = selection[0];
} else {
selectedPoint = null;
}
myLineChart.getChart().setSelection( selection );
}
}
function mouseMoveScript( e ){
var x = e.clientX;
var y = e.clientY;
var coor = "Coordinates: (" + x + "," + y + ")";
document.getElementById("output").innerHTML = coor;
if( selectedPoint != null ){
var chartContainer = document.getElementById( myLineChart.getContainerId() );
var chartBounds = chartContainer.getBoundingClientRect();
var chartLayout = myLineChart.getChart().getChartLayoutInterface()
var chartAreaBounds = chartLayout.getChartAreaBoundingBox();
var chartMinX = chartLayout.getHAxisValue( chartAreaBounds.left );
var chartMaxX = chartLayout.getHAxisValue( chartAreaBounds.left + chartAreaBounds.width );
var chartMinY = chartLayout.getVAxisValue( chartAreaBounds.top + chartAreaBounds.height );
var chartMaxY = chartLayout.getVAxisValue( chartAreaBounds.top );
var dataTable = myLineChart.getDataTable();
var spX = ( x - chartBounds.left - chartAreaBounds.left ) / chartAreaBounds.width * ( chartMaxX - chartMinX );
var spY = ( chartAreaBounds.height - ( y - chartBounds.top - chartAreaBounds.top ) ) / chartAreaBounds.height * ( chartMaxY - chartMinY );
dataTable.setValue( selectedPoint.row, 0, spX );
dataTable.setValue( selectedPoint.row, selectedPoint.column, spY );
drawChart();
}
}
function mouseDownScript( e ){
var mx = e.clientX;
var my = e.clientY;
if( e.target ){
targ = e.target;
selectPoints( mx, my );
} else if (e.srcElement) {
targ = e.srcElement;
}
var tname;
tname = targ.tagName;
}
function mouseUpScript( e ){
if( selectedPoint != null ){
selectedPoint = null;
}
}
html, body {
height: 100%;
margin: 0px 0px 0px 0px;
padding: 0px 0px 0px 0px;
}
#select_div {
border: 1px dashed #3366cc;
position: absolute;
z-index: 1000;
}
.exampleChart{
height: 100%;
}
.hidden {
display: none;
visibility: hidden;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="output"></div>
<div>
<div id="exampleChart" style="width: 900px; height: 500px;"></div>
</div>

Related

JointJS create multiple links between elements

I'm trying create a diagram like this using JointJS.
However, when I'm adding multiple links between elements, I'm only seeing 1 link show up. How do I go about adding multiple links with automatically adjusted space between them?
This is the code to add the boxes and links. Note that right now I'm just trying to add 3 links between all of the blocks, but I'm only seeing 1 link appear between each.
var steps = [{title: "Step 1"}, {title: "Step 2"}, {title: "Step 3"}];
steps.forEach(function(step, i){
var title = step.title;
var yOffset = i*150 + 50; //offsets first block by 50 in y and all others 150
var xOffset = 60; //offsets all blocks by 60
createBlock(title, xOffset, yOffset, i);
});
var blocks = [];
function createBlock(title, x, y, loc) {
var x = (typeof x !== 'undefined') ? x : 0;
var y = (typeof y !== 'undefined') ? y : 0;
var newBlock = new joint.shapes.html.Element({
position: { x: x, y: y },
size: { width: 170, height: 100 },
label: title,
attrs: {
'.label': {
text: title,
'ref-x': .5,
'ref-y': .4,
fill: '#FFFFFF'
},
}
});
blocks.push(newBlock.id);
graph.addCell(newBlock);
if(blocks.length > 1) {
var link = new joint.shapes.devs.Link({
source: {
id: blocks[loc-1],
},
target: {
id: blocks[loc],
},
});
graph.addCell(link);
var link2 = new joint.shapes.devs.Link({
source: {
id: blocks[loc-1],
},
target: {
id: blocks[loc],
},
});
graph.addCell(link2);
var link3 = new joint.shapes.devs.Link({
source: {
id: blocks[loc-1],
},
target: {
id: blocks[loc],
},
});
graph.addCell(link3);
}
}
all the links are lying on top of each other so you see it as a single one. There is code in the demo of jointjs to see each link in different paths. you could add the below code and see that the links show up in different paths. You will need to change the graph to your graph name in the below three lines
// displaying multiple links between two elements in different paths
function adjustVertices(graph, cell) {
// If the cell is a view, find its model.
cell = cell.model || cell;
if (cell instanceof joint.dia.Element) {
_.chain(graph.getConnectedLinks(cell)).groupBy(function(link) {
// the key of the group is the model id of the link's source or target, but not our cell id.
return _.omit([link.get('source').id, link.get('target').id], cell.id)[0];
}).each(function(group, key) {
// If the member of the group has both source and target model adjust vertices.
if (key !== 'undefined') adjustVertices(graph, _.first(group));
});
return;
}
// The cell is a link. Let's find its source and target models.
var srcId = cell.get('source').id || cell.previous('source').id;
var trgId = cell.get('target').id || cell.previous('target').id;
// If one of the ends is not a model, the link has no siblings.
if (!srcId || !trgId) return;
var siblings = _.filter(graph.getLinks(), function(sibling) {
var _srcId = sibling.get('source').id;
var _trgId = sibling.get('target').id;
return (_srcId === srcId && _trgId === trgId) || (_srcId === trgId && _trgId === srcId);
});
switch (siblings.length) {
case 0:
// The link was removed and had no siblings.
break;
case 1:
// There is only one link between the source and target. No vertices needed.
cell.unset('vertices');
break;
default:
// There is more than one siblings. We need to create vertices.
// First of all we'll find the middle point of the link.
var srcCenter = graph.getCell(srcId).getBBox().center();
var trgCenter = graph.getCell(trgId).getBBox().center();
var midPoint = joint.g.line(srcCenter, trgCenter).midpoint();
// Then find the angle it forms.
var theta = srcCenter.theta(trgCenter);
// This is the maximum distance between links
var gap = 20;
_.each(siblings, function(sibling, index) {
// We want the offset values to be calculated as follows 0, 20, 20, 40, 40, 60, 60 ..
var offset = gap * Math.ceil(index / 2);
// Now we need the vertices to be placed at points which are 'offset' pixels distant
// from the first link and forms a perpendicular angle to it. And as index goes up
// alternate left and right.
//
// ^ odd indexes
// |
// |----> index 0 line (straight line between a source center and a target center.
// |
// v even indexes
var sign = index % 2 ? 1 : -1;
var angle = joint.g.toRad(theta + sign * 90);
// We found the vertex.
var vertex = joint.g.point.fromPolar(offset, angle, midPoint);
sibling.set('vertices', [{ x: vertex.x, y: vertex.y }]);
});
}
};
var myAdjustVertices = _.partial(adjustVertices, graph);
// adjust vertices when a cell is removed or its source/target was changed
graph.on('add remove change:source change:target', myAdjustVertices);
// also when an user stops interacting with an element.
graph.on('cell:pointerup', myAdjustVertices);
The core of the solution lies in the adjustVertices function presented below. It accepts a graph and a cell (link or element). For added convenience, the function accepts cell views as well as models.
If cell is a link, it will find all links with the same source and target and then set vertices on them; we will be calling those related links 'siblings'.
If cell is an element, we execute our function for each distinct (different source and target) link connected to the element.
function adjustVertices(graph, cell) {
// if `cell` is a view, find its model
cell = cell.model || cell;
if (cell instanceof joint.dia.Element) {
// `cell` is an element
_.chain(graph.getConnectedLinks(cell))
.groupBy(function(link) {
// the key of the group is the model id of the link's source or target
// cell id is omitted
return _.omit([link.source().id, link.target().id], cell.id)[0];
})
.each(function(group, key) {
// if the member of the group has both source and target model
// then adjust vertices
if (key !== 'undefined') adjustVertices(graph, _.first(group));
})
.value();
return;
}
// `cell` is a link
// get its source and target model IDs
var sourceId = cell.get('source').id || cell.previous('source').id;
var targetId = cell.get('target').id || cell.previous('target').id;
// if one of the ends is not a model
// (if the link is pinned to paper at a point)
// the link is interpreted as having no siblings
if (!sourceId || !targetId) return;
// identify link siblings
var siblings = _.filter(graph.getLinks(), function(sibling) {
var siblingSourceId = sibling.source().id;
var siblingTargetId = sibling.target().id;
// if source and target are the same
// or if source and target are reversed
return ((siblingSourceId === sourceId) && (siblingTargetId === targetId))
|| ((siblingSourceId === targetId) && (siblingTargetId === sourceId));
});
var numSiblings = siblings.length;
switch (numSiblings) {
case 0: {
// the link has no siblings
break;
} case 1: {
// there is only one link
// no vertices needed
cell.unset('vertices');
break;
} default: {
// there are multiple siblings
// we need to create vertices
// find the middle point of the link
var sourceCenter = graph.getCell(sourceId).getBBox().center();
var targetCenter = graph.getCell(targetId).getBBox().center();
var midPoint = g.Line(sourceCenter, targetCenter).midpoint();
// find the angle of the link
var theta = sourceCenter.theta(targetCenter);
// constant
// the maximum distance between two sibling links
var GAP = 20;
_.each(siblings, function(sibling, index) {
// we want offset values to be calculated as 0, 20, 20, 40, 40, 60, 60 ...
var offset = GAP * Math.ceil(index / 2);
// place the vertices at points which are `offset` pixels perpendicularly away
// from the first link
//
// as index goes up, alternate left and right
//
// ^ odd indices
// |
// |----> index 0 sibling - centerline (between source and target centers)
// |
// v even indices
var sign = ((index % 2) ? 1 : -1);
// to assure symmetry, if there is an even number of siblings
// shift all vertices leftward perpendicularly away from the centerline
if ((numSiblings % 2) === 0) {
offset -= ((GAP / 2) * sign);
}
// make reverse links count the same as non-reverse
var reverse = ((theta < 180) ? 1 : -1);
// we found the vertex
var angle = g.toRad(theta + (sign * reverse * 90));
var vertex = g.Point.fromPolar(offset, angle, midPoint);
// replace vertices array with `vertex`
sibling.vertices([vertex]);
});
}
}
}
We then attach the necessary event listeners (function bindInteractionEvents). The vertices are recalculated anytime the user translates an element - as well as anytime a link is added/removed or has its source or target changed.
function bindInteractionEvents(adjustVertices, graph, paper) {
// bind `graph` to the `adjustVertices` function
var adjustGraphVertices = _.partial(adjustVertices, graph);
// adjust vertices when a cell is removed or its source/target was changed
graph.on('add remove change:source change:target', adjustGraphVertices);
// adjust vertices when the user stops interacting with an element
paper.on('cell:pointerup', adjustGraphVertices);
}

Vis.js won't zoom-in further than scale 1.0 with .fit()

I am using the library Vis.js to display a Network.
For my application, I need the network to be displayed fullscreen, with the nodes almost touching the borders of its container.
The problem comes from network.fit(); it won't Zoom-In further than scale '1.0'
I wrote a Fiddle to showcase the issue:
http://jsfiddle.net/v1467x1d/12/
var nodeSet = [
{id:1,label:'big'},
{id:2,label:'big too'} ];
var edgeSet = [
{from:1, to:2} ];
var nodes = new vis.DataSet(nodeSet);
var edges = new vis.DataSet(edgeSet);
var container = document.getElementById('mynetwork');
var data = {
nodes: nodes,
edges: edges
};
var options = {};
var network = new vis.Network(container, data, options);
network.fit();
console.log( 'scale: '+ network.getScale() ); // Always 1
How can I force Vis to zoom until the network is fullscreen?
As Richard said - now, this method does not work as expected. You can use a custom method, as a concept:
function bestFit() {
network.moveTo({scale:1});
network.stopSimulation();
var bigBB = { top: Infinity, left: Infinity, right: -Infinity, bottom: -Infinity }
nodes.getIds().forEach( function(i) {
var bb = network.getBoundingBox(i);
if (bb.top < bigBB.top) bigBB.top = bb.top;
if (bb.left < bigBB.left) bigBB.left = bb.left;
if (bb.right > bigBB.right) bigBB.right = bb.right;
if (bb.bottom > bigBB.bottom) bigBB.bottom = bb.bottom;
})
var canvasWidth = network.canvas.body.container.clientWidth;
var canvasHeight = network.canvas.body.container.clientHeight;
var scaleX = canvasWidth/(bigBB.right - bigBB.left);
var scaleY = canvasHeight/(bigBB.bottom - bigBB.top);
var scale = scaleX;
if (scale * (bigBB.bottom - bigBB.top) > canvasHeight ) scale = scaleY;
if (scale>1) scale = 0.9*scale;
network.moveTo({
scale: scale,
position: {
x: (bigBB.right + bigBB.left)/2,
y: (bigBB.bottom + bigBB.top)/2
}
})
}
[ http://jsfiddle.net/dv4qyeoL/ ]
I am sorry it is impossible to do this using network.fit. Here is the relevant code.
However, you can patch it yourself and include the modified version into your application which should then work as expected.
Here is a fiddle (line 38337 for the modification). I can't promise it won't break something else though.
Relevant code :
/*if (zoomLevel > 1.0) {
zoomLevel = 1.0;
} else if (zoomLevel === 0) {
zoomLevel = 1.0;
}*/
if (zoomLevel === 0) {
zoomLevel = 1.0;
}

Add Link to X-Label Chart.js

I'm looking to be able to link the x-labels in a Chart.js bar chart. I've searched pretty thoroughly, and ended up trying to come up with my own solution: because the labels correspond to the bars directly above them and Chart.js has a built in getBarsAtEvent(evt) method, I tried creating an event if the user didn't click on a chart - this new event had pageX and pageY that was directly above the initial click such that if the user had clicked on a label, the new event would simulate a click on the bar graph.
However, calling getBarsAtEvent(createdClickEvent) repeatedly gives me a Uncaught TypeError ("Cannot read property 'getBoundingClientRect' of null"), which must mean that the getBarsAtEvent method, when called on my simulated click, isn't actually returning anything.
Any suggestions or alternate approaches would be greatly appreciated, thanks in advance.
An alternative approach would be to determine the point where the user is actually clicked and based on that calculate which label was clicked. For that you will need some information about the chart created and have to do some calculations.
Below is a way of doing that, and here is a Fiddle with this code/approach. Hope it helps.
$("#canvas").click(
function(evt){
var ctx = document.getElementById("canvas").getContext("2d");
// from the endPoint we get the end of the bars area
var base = myBar.scale.endPoint;
var height = myBar.chart.height;
var width = myBar.chart.width;
// only call if event is under the xAxis
if(evt.pageY > base){
// how many xLabels we have
var count = myBar.scale.valuesCount;
var padding_left = myBar.scale.xScalePaddingLeft;
var padding_right = myBar.scale.xScalePaddingRight;
// calculate width for each label
var xwidth = (width-padding_left-padding_right)/count;
// determine what label were clicked on AND PUT IT INTO bar_index
var bar_index = (evt.offsetX - padding_left) / xwidth;
// don't call for padding areas
if(bar_index > 0 & bar_index < count){
bar_index = parseInt(bar_index);
// either get label from barChartData
console.log("barChartData:" + barChartData.labels[bar_index]);
// or from current data
var ret = [];
for (var i = 0; i < myBar.datasets[0].bars.length; i++) {
ret.push(myBar.datasets[0].bars[i].label)
};
console.log("current data:" + ret[bar_index]);
// based on the label you can call any function
}
}
}
);
I modified iecs's answer to work with chartjs 2.7.1
var that = this;
this.chart = new Chart($("#chart"), {
type: 'bar',
data: {
labels: labels,
datasets: datasets
},
options: {
events: ["mousemove", "mouseout", "click", "touchstart", "touchmove", "touchend"],
onClick: function(e, data) {
var ctx = $("#chart")[0].getContext("2d");
var base = that.chart.chartArea.bottom;
var height = that.chart.chart.height;
var width = that.chart.chart.scales['x-axis-0'].width;
var offset = $('#chart').offset().top - $(window).scrollTop();
if(e.pageY > base + offset){
var count = that.chart.scales['x-axis-0'].ticks.length;
var padding_left = that.chart.scales['x-axis-0'].paddingLeft;
var padding_right = that.chart.scales['x-axis-0'].paddingRight;
var xwidth = (width-padding_left-padding_right)/count;
// don't call for padding areas
var bar_index = (e.offsetX - padding_left - that.chart.scales['y-axis-0'].width) / xwidth;
if(bar_index > 0 & bar_index < count){
bar_index = Math.floor(bar_index);
console.log(bar_index);
}
}
}
}
});
The main differences are:
The newer versions of chartjs use an chart.scales array instead of chart.scale with a bunch of values
I had to subtract chart.scales['y-axis-0'].width from the x offset to get the correct bar_index
I changed parseInt to Math.floor, just personal preference
And if you want the cursor to change when you hover over them, add "hover" to the events array and this to the options:
onHover: function(e) {
var ctx = $("#chart")[0].getContext("2d");
var base = that.chart.chartArea.bottom;
var height = that.chart.chart.height;
var width = that.chart.chart.scales['x-axis-0'].width;
var yOffset = $('#chart').offset().top - $(window).scrollTop();
var xOffset = $('#chart').offset().left - $(window).scrollLeft();
var left = xOffset + that.chart.scales['x-axis-0'].paddingLeft + that.chart.scales['x-axis-0'].left;
var right = xOffset + that.chart.scales['x-axis-0'].paddingRight + that.chart.scales['x-axis-0'].left + width;
if(e.pageY > base + yOffset && e.pageX > left && e.pageX < right){
e.target.style.cursor = 'pointer';
}
else {
e.target.style.cursor = 'default';
}
}

D3JS filler gauge

Most of the gauge charts are donuts shape, but I am looking to a fill bar dynamic graph similar to the one here.
I am not sure if there is any d3 example which can be dynamic referenced to a dynamic value such as the mouse position as I made in this JSfiddle example where a donut shape gauge is used with the code I found on http://bl.ocks.org/tomerd/1499279 example with some modifications:
var gauges = [];
var w = window.innerWidth;
var h = window.innerHeight;
function createGauge(name, label, min, max)
{
var config =
{
size: 120,
label: label,
min: undefined != min ? min : 0,
max: undefined != max ? max : 100,
minorTicks: 5
}
gauges[name] = new Gauge(name + "GaugeContainer", config);
gauges[name].render();
}
function createGauges()
{
createGauge("xMouse", "X - Mouse");
createGauge("yMouse", "Y - Mouse");
}
function initialize()
{
createGauges();
$( document ).on( "mousemove", function( event ) {
gauges["xMouse"].redraw(100*event.pageX/w);
gauges["yMouse"].redraw(100*event.pageY/h);
});
}
I know that there are other SVG such as the rectangle, but which is the best way to make a "filler bar" gauge?

Pixijs attach element to another

I'm developing a tool to add various sprites to the stage. When I drag an element I'd like to display o bounding box ( a rectangle ) that need to move accordingly to the dragging item.
To handle the drag functionality I'm using a lib called draggable
This is the constructor of every single object I push on the stage:
function createElement(x, y, ass_id)
{
// create our little bunny friend..
bunny = new PIXI.Sprite(textures[ass_id]);
bunny.scale.x = bunny.scale.y = 0.2;
bunny.draggable({
snap: true,
snapTolerance:0,
grid: [ 50, 50 ],
alpha: 0.5,
mousedown: function(data) {
/*var fishBounds = new PIXI.Rectangle(
-fishBoundsPadding,
-fishBoundsPadding,
viewWidth + fishBoundsPadding * 2,
viewHeight + fishBoundsPadding * 2);*/
texture_w = (data.target.texture.width) * data.target.scale.x;
texture_h = (data.target.texture.height) * data.target.scale.y;
// scale = data.target.scale.x;
var box = new PIXI.Graphics();
box.lineStyle(2, 0x666666);
box.drawRect(data.target.position.x, data.target.position.y, texture_w, texture_h);
box.scale.x = box.scale.y = scale;
stage.addChild(box);
data.target.boundingBox = box;
console.log(data.target.boundingBox.position, data.target.position);
},
drag: function(data) {
offset_x = data.boundingBox.position.x;//data.position;
offset_y = data.boundingBox.position.y;
data.boundingBox.position.x = data.position.x;// * data.scale.x;// - offset_x;
data.boundingBox.position.y = data.position.y;// * data.scale.y;// - offset_y;
console.log(stage.children.length , data.boundingBox.position, data.position, data);
},
mouseup: function(data) {
console.log("drop");
stage.removeChild(data.target.boundingBox);
}
});
// move the sprite to its designated position
bunny.position.x = x;
bunny.position.y = y;
elements.push(bunny);
// add it to the stage
stage.addChild(elements[elements.length-1]);
}
now, this works like a charm: when I click the element a bounding box gets created in the correct location, the problem is that when I start drag it around the bounding box get away from the item. I thing that the reason for this might be due to the fact the one item is scaled, wether the other isn't, but since I'm a noob at pixi I really find myself stuck with it.
Ok, I discovered that you can easily and conveniently attach an object to another via the addChild, so it comes out like this:
function createElement(x, y, ass_id)
{
// create our little bunny friend..
bunny = new PIXI.Sprite(textures[ass_id]);
bunny.scale.x = bunny.scale.y = 0.2;
bunny.draggable({
snap: true,
snapTolerance:0,
grid: [ 50, 50 ],
alpha: 0.5,
mousedown: function(data) {
texture_w = (data.target.texture.width);
texture_h = (data.target.texture.height);
var box = new PIXI.Graphics();
box.lineStyle(5, 0x666666);
box.drawRect(0, 0, texture_w, texture_h);
data.target.type = "element";
data.target.addChild(box);
},
drag: function(data) {
},
mouseup: function(data) {
console.log("drop");
for (var i = stage.children.length - 1; i >= 0; i--) {
if((stage.children[i].type) && (stage.children[i].type == "element"))
for (var j = stage.children[i].length - 1; i >= 0; i--) {
console.log('remove boundingBox child here when needed');
}
};
}
});
// move the sprite to its designated position
bunny.position.x = x;
bunny.position.y = y;
elements.push(bunny);
// add it to the stage
stage.addChild(elements[elements.length-1]);
}

Categories