How can I render circles around rectangle in Konva js? - javascript

I need to render table and chairs like in this picture:
I dont know how to calculate position of circles around rect. I tried some code, but its not working...Anybody knows how to solve it?
Check my code:
let smallCircleRadius = 20
let tableSize = {
width: ((seats-4/2)*(smallCircleRadius)),
height: ((seats-4/2)*(smallCircleRadius))
}
let controlY = 0
let totalCircleSide = (seats-4)/2
let controlX = 0
let distanceY = 0
let distanceX = 0
let table = new Konva.Rect({
width: tableSize.width,
height: tableSize.height,
fill: '#fff',
stroke: '#c3c6cf',//'#b2cfcf',
strokeWidth: 8,
x:150,
y: 150
});
let count = 0
group.add(table)
for (var i = 0; i < seats; i++) {
// let distanceToTable = tableSize.width/2;
// let x = i <= 2 ? table.x() + distanceToTable * i + (smallCircleRadius + 8) : count > totalCircleSide ? distanceToTable + distanceX+smallCircleRadius: controlX
// let y = i < 2 ? table.y() - distanceToTable/2: count > totalCircleSide ? controlY : distanceToTable + distanceY*smallCircleRadius
//let x = table.x()
//let y = table.y()
group.add(new Konva.Circle({ radius: smallCircleRadius, fill: '#d2d6df', stroke: '#c3c6cf',strokeWidth: 3, x, y }));
}

Make yourself a simple model that describes the position of the circles in simple relationship of circles to the table. Something like this can be extended via different models to accommodate other table layouts as the description of the layout is entirely in the model data.
const
// Set up a canvas stage
containerEle = document.getElementById('container'),
stage = new Konva.Stage({
container: "container",
size: {
width: containerEle.offsetWidth,
height: containerEle.offsetHeight
}
}),
layer = new Konva.Layer();
stage.add(layer);
const model = {
table: {
x: 100,
y: 100,
width: 200,
height: 400,
fill: 'black',
stroke: 'silver',
strokeWidth: 5
},
seat: {
radius: 40,
fill: 'white',
stroke: 'silver',
strokeWidth: 5,
gap: 20
},
seats: [{
name: "Seat 1",
x: "25%",
y: "-1r"
},
{
name: "Seat 2",
x: "75%",
y: "-1r"
},
{
name: "Seat 3",
tableX: 1,
tableY: 0,
x: "1r",
y: "16.6%"
},
{
name: "Seat 4",
tableX: 1,
tableY: 0,
x: "1r",
y: "50%"
},
{
name: "Seat 5",
tableX: 1,
tableY: 0,
x: "1r",
y: "83.3%"
},
{
name: "Seat 6",
tableX: 0,
tableY: 1,
x: "75%",
y: "1r"
},
{
name: "Seat 7",
tableX: 0,
tableY: 1,
x: "25%",
y: "1r"
},
]
}
// make the table
const table = new Konva.Rect(model.table);
layer.add(table)
for (const seat of model.seats) {
const seatShape = new Konva.Circle(model.seat);
let tablePos = {
x: seat.tableX && seat.tableX === 1 ? model.table.x + model.table.width : model.table.x,
y: seat.tableY && seat.tableY === 1 ? model.table.y + model.table.height : model.table.y
}
let position = {
x: tablePos.x + getPosComponent(seat.x, model.seat.radius, model.table.width, model.seat.gap),
y: tablePos.y + getPosComponent(seat.y, model.seat.radius, model.table.height, model.seat.gap)
}
seatShape.position(position)
layer.add(seatShape);
}
function getPosComponent(val, radius, size, gap) {
if (val.indexOf('r') > 0) {
let num = parseInt(val),
sign = Math.sign(num);
return sign * ((Math.abs(num) * radius) + gap);
} else if (val.indexOf('%') > 0) {
let num = parseFloat(val),
sign = Math.sign(num);
return sign * (size * num / 100);
}
throw new Error("Unexpected val format " + val);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=UTF-8>
<script src="https://unpkg.com/konva#8/konva.min.js"></script>
<style>
#container {
width: 800px;
height: 600px;
}
</style>
</head>
<body>
<div id="container"></div>
</body>
</html>

Related

PhaserRexUI Plugin Not displaying

So I've been trying to use the RexRainbow Phaser UI plugin, and All the Ui i make is invisible for some reason, But when I draw boundaries, it draws them, leaving me with a bunch of red boxes. Why are they all invisible?
Code Here (Github Gist)
//UI
var tabs = this.rexUI.add
.tabs({
x: 400,
y: 1600,
panel: this.rexUI.add.gridTable({
background: this.rexUI.add.roundRectangle(
0,
0,
20,
10,
10,
0x4e342e
),
table: {
width: 250,
height: 400,
cellWidth: 120,
cellHeight: 60,
columns: 1,
mask: {
padding: 2,
},
},
slider: {
//scroll bar
track: this.rexUI.add.roundRectangle(
0,
0,
20,
10,
10,
this.COLOR_DARK
),
thumb: this.rexUI.add.roundRectangle(
0,
0,
5,
40,
10,
this.COLOR_LIGHT
),
}
.layout()
.drawBounds(this.add.graphics(), 0xff0000); //debug for ui
https://codepen.io/vatsadev/pen/dyqGNBG -> full working example
It is hard too say, but I just can assume, that the reason is, that the color's used (that are not visible) are probally undefined and that's why transparent/invisible.
Without knowing the whole code, it is best to check, the variables/properties used for colors (like: this.COLOR_LIGHT, this.COLOR_DARK, ...)
Especially line 62, since here the this context is local to the tabs- object, and is not the scene object.
Tipp: for debugging purposes, I would hardcode all colors, just to see if the setup works, as intended. If so start replacing the hardcoded values with variables, like this you will find the culprit fast.
document.body.style = 'margin:0;';
const COLOR_PRIMARY = 0x4e342e;
const COLOR_LIGHT = 0x7b5e57;
const COLOR_DARK = 0x260e04;
var config = {
type: Phaser.AUTO,
width: 536,
height: 283,
scene: {
preload,
create
}
};
var isLeaking = false;
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');
this.load.scenePlugin({
key: "rexuiplugin",
url: "https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rexuiplugin.min.js",
sceneKey: "rexUI",
});
}
function create () {
let map = this.make.tilemap({ key: 'map', tileWidth: 16, tileHeight: 16 });
let tileset = map.addTilesetImage('tiles');
let fgLayer = map.createLayer(0, tileset, 0, 0);
createUi(this);
updateMap(map);
}
function updateMap (map) {
let originPoint1 = map.getTileAtWorldXY(200, 100);
console.info(map.layers.sort((a,b) => b.depth - a.depth))
map.forEachTile(function (tile) {
var dist = Phaser.Math.Distance.Chebyshev(
originPoint1.x,
originPoint1.y,
tile.x,
tile.y
);
tile.setAlpha(1 - 0.09 * dist);
});
}
function createDataBase () {
var inventory = ['grass', 2, 'dirt', 3, 'wood', 2, 'leaves', 2, ]
// Create the database
var db = new loki();
// Create a collection
var items = db.addCollection("items");
// Insert documents
for (var i = 0; i < inventory.length; i+=2) {
items.insert({
blockType: inventory[i],
quantity: inventory[i+1],
color: Phaser.Math.Between(0, 0xffffff),
});
}
return items;
};
function createUi(scene){
var db = createDataBase();
var tabs = scene.rexUI.add
.tabs({
x: 250,
y: 250,
panel: scene.rexUI.add.gridTable({
background: scene.rexUI.add.roundRectangle(
0,
0,
20,
10,
10,
COLOR_PRIMARY
),
table: {
width: 250,
height: 400,
cellWidth: 120,
cellHeight: 60,
columns: 1,
mask: {
padding: 2,
},
},
slider: { //scroll bar
track: scene.rexUI.add.roundRectangle(0, 0, 20, 10, 10, COLOR_DARK),
thumb: scene.rexUI.add.roundRectangle(0, 0, 5, 40, 10, COLOR_LIGHT),
},
createCellContainerCallback: function (cell) { // each inventory cell
var scene = cell.scene;
var width = 250;
var height = cell.height;
var item = cell.item;
var index = cell.index;
return scene.rexUI.add.label({
width: width,
height: height,
background: scene.rexUI.add
.roundRectangle(0, 0, 20, 20, 0)
.setStrokeStyle(2, COLOR_DARK),
icon: scene.rexUI.add.roundRectangle( // inventory item texture goes here
0,
0,
20,
20,
10,
item.color
),
text: scene.add.text(0, 0, `${item.blockType}: ${item.quantity}`),
space: {
icon: 10,
left: 15,
},
});
},
}),
leftButtons: [
createButton(scene, 2, "Inv."),
],
space: {
leftButtonsOffset: 20,
leftButton: 1,
},
})
.layout()
.drawBounds(scene.add.graphics(), 0xff0000);
tabs.on(
"button.click",
function () {
// Load items into grid table
var items = db
.chain()
.data();
this.getElement("panel").setItems(items).scrollToTop();
},
tabs
);
tabs.emitButtonClick("left", 0);
}
function createButton (scene, direction, text) {
var radius;
switch (direction) {
case 0: // Right
radius = {
tr: 20,
br: 20,
};
break;
case 2: // Left
radius = {
tl: 20,
bl: 20,
};
break;
}
return scene.rexUI.add.label({
width: 50,
height: 40,
background: scene.rexUI.add.roundRectangle(
0,
0,
50,
50,
radius,
COLOR_DARK
),
text: scene.add.text(0, 0, text, {
fontSize: "18pt",
}),
space: {
left: 10,
},
});
};
new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lokijs/1.5.5/lokijs.min.js"></script>

How to align axis label with extended major gridlines outside the chartarea in google bubble chart

I am using google visualization bubble chart, I need to align the vertical axis labels something like below, I want to align the labels to the margin of the chart not to the axis line, also need 2 lines and extend the major grid line to outside of the chart area.
Also here is the code :
<div data-ng-app="mainApp" data-ng-controller="mainSearchController"
ng-init="ShowChart()">
<div class="row" ng-mouseover="mousepoints($event)">
<div google-chart chart="saleChart"
agc-on-mouseover="showTooltip(row)"
agc-on-mouseout="hideTooltip()">
</div>
<div id="custom_tooltip"
style="position:fixed; border:0px solid #777777;
padding-left:10px; line-height:15px; color:#5f5f5f;
font-family:Arial; background-color:#FFFFFF;
height:auto; width:auto; font-size:10px;">
</div>
</div>
</div>
And here is the angularjs code to bind the chart
var app = angular.module('mainApp', ['googlechart']);
app.controller('mainSearchController', function ($scope) {
$scope.ShowChart = function () {
var saleChart = {};
saleChart.type = 'BubbleChart';
saleChart.cssStyle = "height:100%; width:100%;";
var options = {
sizeAxis: {
maxSize: 7,
minSize: 1
},
fontSize:10,
legend: 'none',
height: 200,
width: 400,
bubble: { stroke: '#fdca0f', opacity: 1 },
colors: ['#fdca0f', '#fdca0f'],
tooltip: {
trigger: 'none'
},
hAxis: {
ticks: [
{ v: 800, f: '2015' },
{ v: 1200, f: '2016' },
{ v: 1600, f: '2017' },
{ v: 2000, f: '2018' },
{ v: 2400, f: '2019' },
{ v: 2800, f: '2020' }
],
gridlines: { color: '#dedede' },
minorGridlines: { color: '#f7f7f7', count: 3 },
textStyle: { color: '#5f5f5f' }
},
vAxis: {
ticks: [
{ v: 1, f: 'Chennai in March' },
{ v: 2, f: 'Mumbai in March' },
{ v: 3, f: 'Delhi in April' },
{ v: 4, f: 'Chennai in April' }
],
gridlines: { color: '#dedede' },
textStyle: { color: '#5f5f5f' }
}
};
var d = [
["Name", "Year", "Place", "", "Sales", "tooltip"],
["", 1000, 2, "", 26, "Sale List"],
["",1200,3,"",28,"Sale List"],
["",1400,3,"",48,"S"],
["",1600,3,"",29,"S"]
];
saleChart.data = d;
$scope.chartData = d;
saleChart.options = options;
$scope.saleChart = saleChart;
}
var mouseX;
var mouseY;
$scope.mousepoints = function (e) {
mouseX = e.pageX;
mouseY = e.pageY;
}
$scope.showTooltip = function (row) {
var x = mouseX;
var y = mouseY + 10;
if (row != null) {
dataTable = google.visualization.arrayToDataTable($scope.chartData);
var v = dataTable.getValue(row, 5);
//var v = $scope.chartData.rows[row][5];
v = v.toString().replace(/,/g, "<br/>")
$('#custom_tooltip').html('<div>' + v + '</div>').css({
'top': y,
'left': x
}).fadeIn('slow');
}
}
$scope.hideTooltip = function () {
$('#custom_tooltip').fadeOut('fast');
}
});
the requested changes can only be made by manually modifying the chart's SVG,
this can be done on the chart's 'ready' event.
first, add the ready event to the <div google-chart> element...
<div google-chart chart="saleChart" agc-on-ready="onReady(chartWrapper)"
agc-on-mouseover="showTooltip(row)" agc-on-mouseout="hideTooltip()">
</div>
then add the listener to the controller...
in order to move the labels down, find the <text> elements,
and the change their 'y' attribute.
as for the grid lines (<rect>), we need to change the 'x' attribute, as well as the 'width'.
not only on the grid lines, but the <rect> elements that contain the grid lines.
// ready event
$scope.onReady = function (chartWrapper) {
// find, move labels
var labels = chartWrapper.getChart().getContainer().getElementsByTagName('text');
Array.prototype.forEach.call(labels, function(label) {
if (label.getAttribute('text-anchor') === 'end') {
var yLabel = parseFloat(label.getAttribute('y')) + (parseFloat(label.getAttribute('font-size')) * 2);
label.setAttribute('y', yLabel);
}
});
// find, expand grid lines
var gridLines = chartWrapper.getChart().getContainer().getElementsByTagName('rect');
Array.prototype.forEach.call(gridLines, function(line) {
if ((line.getAttribute('height') === '1') ||
((line.getAttribute('x') !== '0') &&
((line.getAttribute('fill') === null) || (line.getAttribute('fill') === '#ffffff')))) {
var lineWidth = parseFloat(line.getAttribute('width')) + parseFloat(line.getAttribute('x')) - 2;
line.setAttribute('x', 2);
line.setAttribute('width', lineWidth);
}
});
}
see following working snippet...
var app = angular.module('mainApp', ['googlechart']);
app.controller('mainSearchController', function ($scope) {
$scope.ShowChart = function () {
var saleChart = {};
saleChart.type = 'BubbleChart';
saleChart.cssStyle = "height:100%; width:100%;";
var options = {
sizeAxis: {
maxSize: 7,
minSize: 1
},
fontSize:10,
legend: 'none',
height: 200,
width: 400,
bubble: { stroke: '#fdca0f', opacity: 1 },
colors: ['#fdca0f', '#fdca0f'],
tooltip: {
trigger: 'none'
},
hAxis: {
ticks: [
{ v: 800, f: '2015' },
{ v: 1200, f: '2016' },
{ v: 1600, f: '2017' },
{ v: 2000, f: '2018' },
{ v: 2400, f: '2019' },
{ v: 2800, f: '2020' }
],
gridlines: { color: '#dedede' },
minorGridlines: { color: '#f7f7f7', count: 3 },
textStyle: { color: '#5f5f5f' }
},
vAxis: {
ticks: [
// add line break --> \n
{ v: 1, f: 'Chennai\nin March' },
{ v: 2, f: 'Mumbai\nin March' },
{ v: 3, f: 'Delhi\nin April' },
{ v: 4, f: 'Chennai\nin April' }
],
gridlines: { color: '#dedede' },
textStyle: { color: '#5f5f5f' }
}
};
var d = [["Name", "Year", "Place", "", "Sales", "tooltip"],
["", 1000, 2, "", 26, "Sale List"],
["",1200,3,"",28,"Sale List"],
["",1400,3,"",48,"S"],["",1600,3,"",29,"S"]];
saleChart.data = d;
$scope.chartData = d;
saleChart.options = options;
$scope.saleChart = saleChart;
}
var mouseX;
var mouseY;
$scope.mousepoints = function (e) {
mouseX = e.pageX;
mouseY = e.pageY;
}
$scope.showTooltip = function (row) {
var x = mouseX;
var y = mouseY + 10;
if (row != null) {
dataTable = google.visualization.arrayToDataTable($scope.chartData);
var v = dataTable.getValue(row, 5);
//var v = $scope.chartData.rows[row][5];
v = v.toString().replace(/,/g, "<br/>")
$('#custom_tooltip').html('<div>' + v + '</div>').css({
'top': y,
'left': x
}).fadeIn('slow');
}
}
$scope.hideTooltip = function () {
$('#custom_tooltip').fadeOut('fast');
}
$scope.onReady = function (chartWrapper) {
var labels = chartWrapper.getChart().getContainer().getElementsByTagName('text');
var labelIndex = 0;
var nextLabels = [];
Array.prototype.forEach.call(labels, function(label) {
// find label
if (label.getAttribute('text-anchor') === 'end') {
// move label down
var yLabel = parseFloat(label.getAttribute('y')) + (parseFloat(label.getAttribute('font-size')) * 1.5);
label.setAttribute('y', yLabel);
// set text line 1
var labelText = chartWrapper.getOption('vAxis.ticks')[labelIndex].f.split('\n');
label.textContent = labelText[0].toUpperCase();
// save label
nextLabels.push(label);
labelIndex++;
}
});
// add line 2
nextLabels.forEach(function (label, labelIndex) {
var yLabel = parseFloat(label.getAttribute('y')) + (parseFloat(label.getAttribute('font-size')) + 1);
var nextLabel = label.parentNode.appendChild(label.cloneNode(true));
var labelText = chartWrapper.getOption('vAxis.ticks')[labelIndex].f.split('\n');
nextLabel.textContent = labelText[1];
nextLabel.setAttribute('y', yLabel);
// increase font size of line 1
label.setAttribute('font-size', (parseFloat(label.getAttribute('font-size')) + 1));
// re-align labels to left
var labelWidth = label.getBBox().width;
label.setAttribute('x', labelWidth + 2);
labelWidth = nextLabel.getBBox().width;
nextLabel.setAttribute('x', labelWidth + 2);
});
var gridLines = chartWrapper.getChart().getContainer().getElementsByTagName('rect');
Array.prototype.forEach.call(gridLines, function(line) {
if ((line.getAttribute('height') === '1') ||
((line.getAttribute('x') !== '0') &&
((line.getAttribute('fill') === null) || (line.getAttribute('fill') === '#ffffff')))) {
var lineWidth = parseFloat(line.getAttribute('width')) + parseFloat(line.getAttribute('x')) - 2;
line.setAttribute('x', 2);
line.setAttribute('width', lineWidth);
}
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.8/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-google-chart/0.1.0/ng-google-chart.min.js"></script>
<div data-ng-app="mainApp" data-ng-controller="mainSearchController" ng-init="ShowChart()">
<div class="row" ng-mouseover="mousepoints($event)">
<div google-chart chart="saleChart" agc-on-mouseover="showTooltip(row)" agc-on-mouseout="hideTooltip()" agc-on-ready="onReady(chartWrapper)"></div>
<div id="custom_tooltip" style="position:fixed; border:0px solid #777777; padding-left:10px; line-height:15px; color:#5f5f5f; font-family:Arial; background-color:#FFFFFF; height:auto; width:auto; font-size:10px;"></div>
</div>
</div>
google charts uses clip-path to attach visual graphics. You can take control over this using cx (horizontal axis), cy (vertical axis), and r (radius) attributes on <circle> elements.
As each row will (or must) have same height you can simply add some js to make cy = cy - 10; (or whatever number that makes appear your circle where you want.
BUT there's another issue here, you can't set circles over the top axis, or bottom. Well, you can but it will be half-out of the canvas. At this point i think there's not much to do here, can't use z-index css property on this elements so you may not being able to reach the desired approach.

Regression that fits best scatter plot

I have the following scatter plot plotted and I want to add a linear, polynomial regression (the one that fits best) to my data. Is there any easy way to do it?
My chart is an easy one, done by c3 library v4 (depending on d3 v3):
<div id="chart2"></div>
<script>
var chart = c3.generate({
bindto: '#chart2',
data: {
url: '../static/CSV/Chart_data/grades_access.csv'+(new Date).getTime(),
x:'Access_grade',
type: 'scatter'
},
axis: {
y: {
label: {
text:"Average grade",
position: "outer-middle"
},
min:1,
max:9
},
x: {
label: {
text:"Access grade PAU",
position: "outer-center"
},
min:9,
max:14
}
},
size: {
height: 400,
width: 800
},
zoom: {
enabled: true
},
legend: {
show: true,
position: 'inset',
inset: {
anchor: 'top-right',
x: 20,
y: 300,
step: 1
}
}
});
</script>
And grades_access.csv is:
Access_grade,Subject
9.85,2.5
10.64,8.1
10.0,3.2
10.92,4.0
11.69,2.9
11.79,7.8
11.03,5.0
10.47,6.2
...
Could anyone give me a hint? I want a simple thing, not too sofisticated. But with the equation of the regression if possible :)
Thanks!
I've answered this question a couple time for other libraries but never c3.js. Here's code to fit a linear regression using a simple least squared method. It does it onrendered so that you can still use c3's ability to fetch and parse your csv file:
<div id="chart2"></div>
<script>
var chart = c3.generate({
bindto: '#chart2',
data: {
url: 'data.csv',
x: 'Access_grade',
type: 'scatter'
},
axis: {
y: {
label: {
text: "Average grade",
position: "outer-middle"
},
min: 1,
max: 9
},
x: {
label: {
text: "Access grade PAU",
position: "outer-center"
},
min: 9,
max: 14
}
},
size: {
height: 400,
width: 800
},
zoom: {
enabled: true
},
legend: {
show: true,
position: 'inset',
inset: {
anchor: 'top-right',
x: 20,
y: 300,
step: 1
}
},
onrendered: function(c) {
var points = chart.data()[0].values.map((d) => [d.x, d.value]),
slopeIntercept = slopeAndIntercept(points),
fitPoints = chart.data()[0].values.map((d) => slopeIntercept.slope * d.x + slopeIntercept.intercept);
chart.load({
columns: [
['Regression'].concat(fitPoints)
],
type: 'line'
});
}
});
// simple linear regression
slopeAndIntercept = function(points) {
var rV = {},
N = points.length,
sumX = 0,
sumY = 0,
sumXx = 0,
sumYy = 0,
sumXy = 0;
// can't fit with 0 or 1 point
if (N < 2) {
return rV;
}
for (var i = 0; i < N; i++) {
var x = points[i][0],
y = points[i][1];
sumX += x;
sumY += y;
sumXx += (x * x);
sumYy += (y * y);
sumXy += (x * y);
}
// calc slope and intercept
rV['slope'] = ((N * sumXy) - (sumX * sumY)) / (N * sumXx - (sumX * sumX));
rV['intercept'] = (sumY - rV['slope'] * sumX) / N;
rV['rSquared'] = Math.abs((rV['slope'] * (sumXy - (sumX * sumY) / N)) / (sumYy - ((sumY * sumY) / N)));
return rV;
}
</script>
Here's a running example.

Fabric.js line rendering when resizing object

Have an issue with line rendering when resizing object.
I've locked line endings positions to exact point on circles and when moving, scaling, rotating etc I have to edit lines connected to current circle.
Here is fiddle
Just try to resize circles and at some point you'll see that rendering is crashed a bit which corresponds to lines. Need a help for it, maybe rerender or something.
Or that's an issue of fabric.js
var circlesData = [{
id: 1,
x: 80,
y: 80,
r: 60
}, {
id: 2,
x: 440,
y: 190,
r: 90
}];
var connectionsData = [{
from: {id: 1, angle: 0, rdist: .8},
to: {id: 2, angle: 0, rdist: .4},
}]
var fcircles = [];
var fconnections = [];
var fcanvas;
init();
function init() {
fcanvas = new fabric.Canvas('c', {
imageSmoothingEnabled: false,
allowTouchScrolling: true,
});
fcanvas.preserveObjectStacking = true;
fcanvas.selection = false;
fcanvas.setBackgroundColor('#fff');
fcircles = circlesData.map(function(circleData) {
var circle = new fabric.Circle({
left: circleData.x,
top: circleData.y,
radius: circleData.r,
fill: 'rgba(100,100,255,0.2)',
originX: 'center',
originY: 'center'
});
circle.initialData = circleData;
circle.setControlsVisibility({
mt: false,
mb: false,
ml: false,
mr: false,
mtr: false,
});
return circle;
});
fconnections = connectionsData.map(function(connectionData) {
var line = new fabric.Line([0,0,0,0], {
strokeWidth: 6,
strokeLineCap: 'round',
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center'
});
line.from = copyJson(connectionData.from);
line.to = copyJson(connectionData.to);
line.selectable = false;
return line;
});
fcircles.concat(fconnections).forEach(function(fobj){
fcanvas.add(fobj)
});
updateConnections(fconnections);
fcanvas.renderAll();
console.log(fcanvas.getObjects())
fcanvas.on('object:moving', onObjChange);
fcanvas.on('object:scaling', onObjChange);
fcanvas.on('object:rotating', onObjChange);
}
function onObjChange(e) {
if(['line'].indexOf(e.target.type) > -1) {
return;
}
var circle = e.target;
updateConnections(fconnections.filter(function(fconnection){
return fconnection.from.id === e.target.initialData.id || fconnection.to.id === e.target.initialData.id;
}))
}
function updateConnections(fconnections) {
fconnections.forEach(function(fconnection) {
var from = fcircles.filter(function(c){return c.initialData.id === fconnection.from.id})[0];
var to = fcircles.filter(function(c){return c.initialData.id === fconnection.to.id})[0];
var fromAngle = fconnection.from.angle - from.angle / 180 * Math.PI;
var toAngle = fconnection.to.angle - from.angle / 180 * Math.PI;
debugger;
fconnection.set({
x1: from.left + fconnection.from.rdist * from.radius * Math.cos(fromAngle),
y1: from.top + fconnection.from.rdist * from.radius * Math.sin(fromAngle),
x2: to.left + fconnection.to.rdist * to.radius * Math.cos(toAngle),
y2: to.top + fconnection.to.rdist * to.radius * Math.sin(toAngle)
});
fconnection.setCoords();
});
}
function copyJson(obj) {
return JSON.parse(JSON.stringify(obj));
}
Add to your Line object property:
objectCaching: false
From fabricjs documentation:
objectCaching :Boolean When true, object is cached on an additional
canvas. default to true since 1.7.0

Canvasjs library, dataPoints

I have code like this, if i add dataPoints:
[{ x: 50, y: 280 },{ x: 60, y: 507 }] it works.
But in the code below, the [{ x: 50, y: 280 },{ x: 60, y: 507 }] is in the variable rss, it not working.
<script type="text/javascript">
window.onload = function () {
var year = ('<?php echo $rs; ?>');
var jsontoarray = JSON.parse(year);
var props = Object.keys(jsontoarray);
var rss = "[";
for (var i = 0; i < props.length; i++) {
rss += "{ x: " + props[i] + ", y: " + jsontoarray[props[i]] + "},";
}
rss = rss.substr(0, rss.length - 1); //bỏ dấu , cuối cùng
rss += "]";
var chart = new CanvasJS.Chart("chartContainer", {
title: {
text: "Column Chart with Index Label and Data Point Width"
},
axisX: {
interval: 10
},
dataPointWidth: 60,
data: [{
type: "column",
indexLabelLineThickness: 2,
dataPoints: rss
}]
});
chart.render();
}
</script>
<div id="chartContainer" style="height: 400px; width: 95%; margin: auto;"></div>
It's not working because rss is seen as a string, not as an array.
You'll need to do something like this:
var rss = [];
for (var i = 0; i < props.length; i++) {
rss.push({
x: props[i],
y: jsontoarray[props[i]]
});
}

Categories

Resources