FabricJS and AngularJS – copy and paste object with custom attribute - angularjs

I'm using some custom attributes while I'm creating my objects. For example in this case "name" and "icon":
$scope.addRoundRect = function () {
var coord = getRandomLeftTop();
var roundrect = (new fabric.Rect({
left: coord.left,
top: coord.top,
fill: '#' + getRandomColor(),
width: 250,
height: 250,
opacity: 1,
scaleX: 1,
scaleY: 1,
angle: 0,
rx: 10,
ry: 10,
strokeWidth: 0,
name: "Rounded Rectangle",
icon: "crop-square"
}));
canvas.add(roundrect).setActiveObject(roundrect);
};
This is my copy/paste function. As you can see I have already tried to paste the relevant attributes – bu I think that they are simply not cloned with the object:
function copy() {
canvas.getActiveObject().clone(function (cloned) {
_clipboard = cloned;
});
}
function paste() {
_clipboard.clone(function (clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
name: clonedObj.name,
icon: clonedObj.icon,
});
if (clonedObj.type === 'activeSelection') {
clonedObj.canvas = canvas;
clonedObj.forEachObject(function (obj) {
canvas.add(obj);
});
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
});
To make it short: is there a way to clone and paste also this attributes without having to modify the source (ie. impleneting a full fledged custom attribute in the JSO serialization)?

var canvas = new fabric.Canvas('c');
var roundrect = new fabric.Rect({
left: 50,
top: 30,
fill: 'blue',
width: 250,
height: 250,
opacity: 1,
scaleX: 1,
scaleY: 1,
angle: 0,
rx: 10,
ry: 10,
strokeWidth: 0,
name: "Rounded Rectangle",
icon: "crop-square"
});
canvas.add(roundrect).setActiveObject(roundrect);
var customProperties = 'name icon'.split(' ');
function copy() {
canvas.getActiveObject().clone(function(cloned) {
console.log(cloned);
_clipboard = cloned;
}, customProperties);
}
function paste() {
// clone again, so you can do multiple copies.
_clipboard.clone(function(clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
});
if (clonedObj.type === 'activeSelection') {
// active selection needs a reference to the canvas.
clonedObj.canvas = canvas;
clonedObj.forEachObject(function (obj) {
canvas.add(obj);
});
// this should solve the unselectability
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
console.log(clonedObj);
_clipboard = clonedObj;
},customProperties);
}
canvas {
border: blue dotted 2px;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<button onclick='copy()'>copy</button>
<button onclick='paste()'>paste</button><br>
<canvas id="c" width="400" height="400"></canvas>
object.clone accepts callback function and any additional property you want to include as another parameter. You can send your name and icon as properties to include.
And in paste you no need to clone that object if you are doing so, make sure there also send you are including your additional properties.

Related

TradingView - Lightweight charts - Realtime histogram ( volume indicator)

I managed to get the real time example to work:
https://jsfiddle.net/TradingView/yozeu6k1/
I tried to get a real time histogram underneath, as the usual volume indicator and the behavior is random.
A snapshot of the chart:
enter image description here
As we can see the starting point of those bars differ one from another.
Series definition:
const volumeSeries = chart.addHistogramSeries({
priceFormat: {
type: 'volume',
},
priceScaleId: '',
scaleMargins: {
top: 0.8,
bottom: 0,
}
});
Update:
volumeSeries.update({
time: data.time,
value: data.volume
});
Can anyone point me to an example in order to get a candlestick chart with a volume indicator to work? Both updating in real time.
I got it to work, basically the issue was that the histogram understands negative values as a down facing bar, so in order to show a volume indicator we have to show the absolute value of the volume and change the color.
A working example at: https://jsfiddle.net/rondolfo/0zg7u9tv/57/
//colours
var green = 'rgb(38,166,154)';
var red = 'rgb(255,82,82)';
var black = '#000000';
var white = 'rgba(255, 255, 255, 0.9)';
var grey = 'rgba(42, 46, 57, 0.5)';
// chart definition
var chart = LightweightCharts.createChart(document.body, {
width: 800,
height: 400,
layout: {
backgroundColor: black,
textColor: white,
},
grid: {
vertLines: {
visible: false,
},
horzLines: {
color: grey,
},
},
crosshair: {
mode: LightweightCharts.CrosshairMode.Normal,
}
});
chart.applyOptions({
timeScale: {
borderVisible: false,
borderColor: '#fff000',
visible: true,
timeVisible: true,
minBarSpacing: 0.0,
}
});
const candleStickSeries = chart.addCandlestickSeries({
upColor: green,
downColor: red,
wickUpColor: green,
wickDownColor: red,
borderVisible: false,
priceLineVisible: false,
});
const volumeSeries = chart.addHistogramSeries({
priceFormat: {
type: 'volume',
},
priceScaleId: '',
scaleMargins: {
top: 0.8,
bottom: 0.02,
}
});
//end chart definition
//data loading
jQuery.ajaxSetup({
async: false
});
var url = 'https://raw.githubusercontent.com/AnAlgoTrader/TradingView.LightWeightCharts.Example/main/InputData/prices.json';
var data = [];
$.get(url, function(result) {
data = JSON.parse(result);
});
//end data loading
//real time updates
var index = 0;
setInterval(function() {
if (index > data.length) return;
var item = data[index];
candleStickSeries.update({
time: item.time,
open: item.open,
high: item.high,
low: item.low,
close: item.close
});
var volumeColour = item.volume < 0 ? red : green;
volumeSeries.update({
time: item.time,
value: Math.abs(item.volume),
color: volumeColour
});
index++;
}, 1000);

Chartist graphs get re-drawn everytime I click on any button or resize window

I really like this library, but I can't seem to control this issue somehow. If any event occurs the graphs are being re-drawn every time.
I am using React.js and this is how I am creating and displaying the Chartist graphs:
const dailyComplaintsChart = {
data: {
labels: ["M", "T", "W", "T", "F", "S", "S"],
series: [whichType.seriesDaily]
},
options: {
lineSmooth: Chartist.Interpolation.cardinal({
tension: 0
}),
low: 0,
high: highestValue.highestValueDaily, // creative tim: we recommend you to set the high sa the biggest value + something for a better look
chartPadding: {
top: 0,
right: 0,
bottom: 0,
left: 0
}
},
// for animation
animation: {
draw: function (data) {
if (data.type === "line" || data.type === "area") {
data.element.animate({
d: {
begin: 600,
dur: 700,
from: data.path
.clone()
.scale(1, 0)
.translate(0, data.chartRect.height())
.stringify(),
to: data.path.clone().stringify(),
easing: Chartist.Svg.Easing.easeOutQuint
}
});
} else if (data.type === "point") {
data.element.animate({
opacity: {
begin: (data.index + 1) * delays,
dur: durations,
from: 0,
to: 1,
easing: "ease"
}
});
}
}
}
};
return(
<div className="daily-graph">
<ChartistGraph
className="ct-chart-background-daily-complaints"
data={dailyComplaintsChart.data}
type="Line"
options={dailyComplaintsChart.options}
listener={dailyComplaintsChart.animation}
/>
<div className={classes.line}>
<p>Daily Complaints</p>
</div>
</div>
)
This problem is caused by the use of animation, So you have to put all the animate function in an if statement and set a counter outside of draw function.
let animated = 0;
draw(data) {
if (animated <= label.length) {
// animate
data.element.animate(...)
animated++;
}
}

How to customize tooltip for forceDirectedGraph in angular nvd3

I am using the force directed graph in angular nv3d. I would like to customize the text color on the nodes as well as modify the tool tip. Ive also been trying to figure out how to force the nodes to be more sparse. Here is my chart object:
chart: {
type: 'forceDirectedGraph',
height: 450,
color: function(d) {
return color(d.Name);
},
tooltipContent: function (key) {
return '<h3>' + key + '</h3>';
},
margin: {top: 20, right: 20, bottom: 20, left: 20},
nodeExtras: function(node) {
node && node
.append('text')
.attr('dx', 15)
.attr('dy', '.35em')
.text(function(d) {
return d.Name;
})
.style('font-size', '25px');
},
},
};
As you can see, I tried adding the tooltipContent property to the chart object to no avail. Any help would be greatly appreciated, thanks!
To customize the tool tip do the following
chart: {
type: 'forceDirectedGraph',
... /* All properties */
height : 400,
tooltip : {
contentGenerator : function (obj) { return "<div> **custom formating** </div>"}
}
}

Include JointJS diagram in React/Flux projects

I'm trying to include a JointJS diagram in my React+Flux project.
I started from an existing demo available there.
My idea is to embed the diagram in an higher level component that will be reused inside my project.
The structure that I came up with is the following:
index.html
...
<body>
<section id="mySec"></section>
...
app.js
...
ReactDOM.render(
<JointJSDiagram id="1"/>,
document.getElementById('mySec')
);
JointJSDiagram.react.js
...
var JointJSDiagramStore = require('../stores/JointJSDiagramStore');
class JointJSDiagram extends React.Component {
...
componentDidMount() {
var el = this.refs[this.props.placeHolder];
document.addEventListener("DOMContentLoaded", function(elt){
return function(){JointJSDiagramStore.buildDiagram(elt)};
}(el), false);
}
...
render() {
return (<div ref={this.props.placeHolder}/>);
}
...
}
module.exports = JointJSDiagram;
JointJSDiagramStore.js
...
var AppDispatcher = require('../dispatcher/AppDispatcher');
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');
var _graph = new joint.dia.Graph();
var _paper = new joint.dia.Paper({
width: 600,
height: 200,
model: _graph,
gridSize: 1
});
var JointJSDiagramStore = assign({}, EventEmitter.prototype, {
...
buildDiagram: function(el) {
_paper.el = el;
// In here I used the code from: http://www.jointjs.com/demos/fsa
function state(x, y, label) {
var cell = new joint.shapes.fsa.State({
position: { x: x, y: y },
size: { width: 60, height: 60 },
attrs: {
...
...
...
link(star, block, 'other', [{x: 650, y: 290}]);
link(star, code, '/', [{x: 490, y: 310}]);
link(line, line, 'other', [{x: 115,y: 100}, {x: 250, y: 50}]);
link(block, block, 'other', [{x: 485,y: 140}, {x: 620, y: 90}]);
link(code, code, 'other', [{x: 180,y: 500}, {x: 305, y: 450}]);
},
...
});
...
module.exports = JointJSDiagramStore;
The problem is that nothing is visualized except for some (7) warnings stating:
Warning: ReactDOMComponent: Do not access .getDOMNode() of a DOM node;
instead, use the node directly. This DOM node was rendered by
JointJSDiagram.
UPDATE
If I explicitly use the id instead of refs like this:
JointJSDiagramStore.js
...
componentDidMount() {
var el = document.getElementById(this.props.placeHolder);
document.addEventListener("DOMContentLoaded", function(elt){
return function(){JointJSDiagramStore.buildDiagram(elt)};
}(el), false);
JointJSDiagramStore.addChangeListener(this._onChange);
}
...
render() {
return (<div id={this.props.placeHolder}/>);
}
...
I don't receive Warnings anymore, but nothing is still displayed on the placeholder div.
This quick test worked for me. I'm using react 0.14.3
class Graph extends React.Component {
constructor(props) {
super(props);
this.graph = new joint.dia.Graph();
}
componentDidMount() {
this.paper = new joint.dia.Paper({
el: ReactDOM.findDOMNode(this.refs.placeholder),
width: 600,
height: 200,
model: this.graph,
gridSize: 1
});
const rect = new joint.shapes.basic.Rect({
position: { x: 100, y: 30 },
size: { width: 100, height: 30 },
attrs: {
rect: { fill: 'blue' },
text: { text: 'my box', fill: 'white' }
}
});
const rect2 = rect.clone();
rect2.translate(300);
const link = new joint.dia.Link({
source: { id: rect.id },
target: { id: rect2.id }
});
this.graph.addCells([rect, rect2, link]);
}
render() {
return <div ref="placeholder" ></div>;
}
}

how can I use array in place of name value pair in a function

In the below code how can I use options array which is passed as a argument to drawOval
drawOval=function(options) {
$triangle = new Triangle({
// how can I use options array here
// the format it accept is top:450,
// left:500,width:200
});
};
opt = new Array(
top: 450,
left: 500,
width: 200,
height: 200,
fill: 'rgb(204,0,107)'
);
drawOval(opt);
Basically I need an object not array.
opt= {
top:100,
left:200,
width:200,
height:200,
fill:'rgb(12,0,107)'
}
drawOval(opt);

Resources