I want to create a custom element with new attributes, I created my custom element like that but I need a new attribute to store information about the element.
joint.shapes.basic.newRect = joint.shapes.basic.Generic.extend({
markup: '<g class="rotatable"><g class="scalable"><rect/></g><text/></g>',
defaults: joint.util.deepSupplement({
type: 'basic.newRect',
attrs: {
'rect': { fill: 'white', stroke: 'black', 'follow-scale': true, width: 80, height: 40 },
'text': { 'font-size': 14, 'ref-x': .5, 'ref-y': .5, ref: 'rect', 'y-alignment': 'middle', 'x-alignment': 'middle' }
}
}, joint.shapes.basic.Generic.prototype.defaults)
Thanks!
You can add new properties next to the type and attrs. These will be your default properties for your element, like so:
joint.shapes.basic.newRect = joint.shapes.basic.Generic.extend({
markup: '<g class="rotatable"><g class="scalable"><rect/></g><text/></g>',
defaults: joint.util.deepSupplement({
type: 'basic.newRect',
attrs: {
'rect': { fill: 'white', stroke: 'black', 'follow-scale': true, width: 80, height: 40 },
'text': { 'font-size': 14, 'ref-x': .5, 'ref-y': .5, ref: 'rect', 'y-alignment': 'middle', 'x-alignment': 'middle' }
},
mycustom: 'foo'
}, joint.shapes.basic.Generic.prototype.defaults)
Later when you instantiate your element, you can also add properties only to that specific element:
var myNewRect = new joint.shapes.basic.newRect({ position: { x: 1, y: 1 }});
myNewRect.set('mycustom2', 'bar')
myNewRect.get('mycustom') // 'foo'
myNewRect.get('mycustom2') // 'bar'
All these properties will be taken into account when serializing the graph as well.
You can also use the provided Element#prop. See http://jointjs.com/api#joint.dia.Element:prop
Related
Does anyone has clue how to target specific grid line and style like in the example?
I know how to dash line with:
grid: {
strokeDashArray: 10,
},
But how can I target grid line according to the tick value?
Desired result
Only way you can do it is via css
.apexcharts-gridline:nth-child(2) {
stroke-dasharray: 10;
}
Or use annotations instead https://apexcharts.com/docs/annotations/
I have sorted it by using annotations property. Here is an example:
// Breakdown line
annotations: {
position: 'front',
yaxis: [
{
y: 3000,
strokeDashArray: 5,
label: {
position: 'left',
borderColor: 'transparent',
textAnchor: 'middle',
offsetY: -10,
offsetX: 50,
style: {
color: '#D0D4D9',
background: "transparent",
},
text: ''
}
}
]
}
I created a custom element using the jointjs tutorial like this:
CustomRect = joint.dia.Element.define('example.CustomRect', {
attrs: {
rect: {
refX: 0,
refY: 0,
refWidth: '116',
refHeight: '70',
strokeWidth: 1,
stroke: '#000000',
fill: '#FFFFFF'
},
label: {
textAnchor: 'left',
refX: 10,
fill: 'black',
fontSize: 18,
text: 'text'
},
upperRect: {
strokeWidth: 1,
stroke: '#000000',
fill: 'rgba(255,0,0,0.3)',
cursor: 'pointer'
}
}
}, {
markup: [{
tagName: 'rect',
selector: 'rect'
},
{
tagName: 'text',
selector: 'label'
},
{
tagName: 'rect',
selector: 'upperRect'
}]
})
...
let customRect = new this.CustomRect()
customRect.attr({
upperRect: {
refWidth: '116',
refHeight: '10',
refX: 0,
refY: -11,
event: 'element:upperRect:pointerdown'
}
})
Furthermore, I tried adding Ports with the Port API for joint.dia.Element like this:
customRect.addPorts([
{
args: {
y: 30
},
z: 0
}
]);
This does add Ports to my element, but they don't have the functionality they should have, so they're just some circles that do nothing.
The method shown in the Port Tutorial does not work, since I'm not using joint.shapes.devs.Model for my custom element, because then I can't customize it like the joint.dia.Element element (or at least I think I can't).
So, how can I add Ports to a custom element defined with joint.dia.Element that have the functionality they should have (as shown in the Port Tutorial)?
Unfortunately, the documentation does not explain this clear enough. If you want to make the ports interactive you need to set the magnet attribute on them.
const CustomRect = joint.dia.Element.define('example.CustomRect', {
/* ... */
attrs: {
root: {
// Don't allow the root of the element to be target of a connection
magnet: false
}
},
ports: {
items: [{
id: 'port1',
attrs: {
portBody: {
// The port can be a target of a connection
// The user can create a link from the port by dragging the port
magnet: true
}
}
}, {
id: 'port2',
attrs: {
portBody: {
// The port can only become a target of a connection
// The logic can be modified via paper.options.validateMagnet()
magnet: 'passive'
}
}
}]
}
}, {
/* ... */
portMarkup: [{
tagName: 'circle',
selector: 'portBody',
attributes: {
'r': 10,
'fill': '#FFFFFF',
'stroke': '#000000'
// If all the magnets are `true` / `passive` feel free to define
// the magnet here in the default port markup or per a port group
// 'magnet': true
}
}]
});
I need to create a div container for a highcharts graphic. This should be done by means of code, but I can not make it work.
The reason to create divs by code is because I have to show many graphics.
Currently I first create the div, then the id and finally the properties.
Error on graphic:
Example :
http://jsfiddle.net/povyq7em/1/
My code is:
var nombre="container-speed";
var div = document.createElement('div');
div.setAttribute("style", "width: 580px; height: 400px; float: left");
div.setAttribute("id", nombre);
var gaugeOptions = {
chart: {
type: 'solidgauge'
},
title: null,
pane: {
center: ['50%', '85%'],
size: '140%',
startAngle: -90,
endAngle: 90,
background: {
backgroundColor: (Highcharts.theme &&
Highcharts.theme.background2) || '#EEE',
innerRadius: '60%',
outerRadius: '100%',
shape: 'arc'
}
},
tooltip: {
enabled: false
},
yAxis: {
stops: [
[0.1, '#55BF3B'], // green
[0.5, '#DDDF0D'], // yellow
[0.9, '#DF5353'] // red
],
lineWidth: 0,
minorTickInterval: null,
tickAmount: 2,
title: {
y: -70
},
labels: {
y: 16
}
},
plotOptions: {
solidgauge: {
dataLabels: {
y: 5,
borderWidth: 0,
useHTML: true
}
}
}
};
var chartSpeed = Highcharts.chart(nombre, Highcharts.merge(gaugeOptions, {
yAxis: {
min: 0,
max: 200,
title: {
text: 'Speed'
}
},
credits: {
enabled: false
},
series: [{
name: 'Speed',
data: [80],
dataLabels: {
format: '<div style="text-align:center"><span style="font-size:25px;color:' +
((Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black') + '">{y}</span><br/>' +
'<span style="font-size:12px;color:silver">km/h</span></div>'
},
tooltip: {
valueSuffix: ' km/h'
}
}]
}));
.highcharts-yaxis-grid .highcharts-grid-line {
display: none;
}
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/solid-gauge.js"></script>
<!--<div id="container-speed" style="width: 300px; height: 200px; float: left"></div>-->
Thank you very much for your help.
You're just missing one step. You need to append the element after you create it. Here's the beginning of your code:
var nombre="container-speed";
var div = document.createElement('div');
div.setAttribute("style", "width: 580px; height: 400px; float: left");
div.setAttribute("id", nombre);
// APPEND ELEMENT TO document.body
document.body.appendChild(div);
Also, I updated your fiddle
Per your request, I updated the fiddle once more. I made 3 changes. Only one of which were really important.
declare and value name to be used as element id and as argument for grafica()
var name = "chart-" + i;
alter setAttribute to div.setAttribute("id", name);
***MOST IMPORTANTLY, you changed the variable nombre to name in every place but here var chartSpeed = Highcharts.chart(name, Highcharts.merge(gaugeOptions, {... which you can tell, I've updated.
What I am trying to do is make a element with custom class for ports and path so that I can add an element with custom path and my own markup for ports.This way when I create an element I will pass dynamic path for its shape just like elements of path class behave and as I have also extended from PortsModelInterface I will also have my own markup for ports.
This whole effort is to make svg scalable for zomming. Previously I was using html custom element with my custom ports which was working fine but html of custom elements wasn't scaling on zooming
var graph = new joint.dia.
var paper = new joint.dia.Paper({
el: $('#paper'),
width: 800,
height: 600,
gridSize: 1,
model: graph,
snapLinks: true,
embeddingMode: true
});
joint.shapes.custom1={};
joint.shapes.custom1.Element = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
markup: '<g class="rotatable"><g class="scalable"><rect class = "myrect"/></g><g class="inPorts"/><g class="outPorts"/></g>',
portMarkup: '<g class="port<%= id %>"><circle class="port-body"/></g>',
defaults: joint.util.deepSupplement({
type: 'html.Element',
size: { width: 200, height: 110 },
inPorts: [],
outPorts: [],
attrs: {
'.': { magnet: true},
rect: {
stroke: 'none', 'fill-opacity': 0, width: 300, height: 210,
},
circle: {
r: 6, //circle radius
magnet: true,
left:0,
stroke: 'gray'
},
'.inPorts circle': { fill: 'gray', magnet: 'passive', type: 'input', y: 0},
'.outPorts circle': { fill: 'gray', type: 'output' }
}
}, joint.shapes.basic.Generic.prototype.defaults),
getPortAttrs: function (portName, index, total, selector, type) {
var attrs = {};
var portClass = 'port' + index;
var portSelector = selector + '>.' + portClass;
var portCircleSelector = portSelector + '>circle';
attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type), type: type } };
attrs[portSelector] = { ref: 'rect', 'ref-x': (index + 1) * (0.55 / total)};
if (selector === '.outPorts') {
attrs[portSelector]['ref-dy'] = 15;
}
return attrs;
}
}));
joint.shapes.custom1.Atomic = joint.shapes.custom1.Element.extend({
markup: '<g class="rotatable"><g class="scalable"><path/></g><text/></g>',
defaults: joint.util.deepSupplement({
type: 'basic.Path',
size: { width: 60, height: 60 },
attrs: {
'path': { fill: '#FFFFFF', stroke: 'black' },
'text': { 'font-size': 14, text: '', 'text-anchor': 'middle', 'ref-x': .5, 'ref-dy': 20, ref: 'path', 'y-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
}
}, joint.shapes.basic.Generic.prototype.defaults)
});
var a2 = new joint.shapes.custom1.Atomic({
position: { x: 50, y: 260 },
size: { width: 100, height: 100 },
attrs: {
path: { d: 'M 30 0 L 60 30 30 60 0 30 z' },
text: {
text: 'Diamond',
'ref-y': .5 // basic.Path text is originally positioned under the element
}
},
inPorts: ['in'],
outPorts: ['out']
});
graph.addCells([a2])
The element is added in graph but some how the ports don't show up.
I don't have proper concept of adding classes so please any help will be greatly appreciated. Thanks.
Fiddle example
I suggest to define an element with custom markup for the shape and ports. Both markups should contain an SVG path, so you can set an arbitrary path data d via model.attr() on them.
joint.shapes.devs.GenericModel = joint.shapes.devs.Model.extend({
markup: '<g class="rotatable"><g class="scalable"><path class="body"/></g><text class="label"/><g class="inPorts"/><g class="outPorts"/></g>',
portMarkup: '<g class="port port<%= id %>"><path class="port-body"/><text class="port-label"/></g>',
defaults: joint.util.deepSupplement({
type: 'devs.GenericModel'
}, joint.shapes.devs.Model.prototype.defaults)
});
Tell the paper to use devs.ModelView for rendering.
joint.shapes.devs.GenericModelView = joint.shapes.devs.ModelView;
Now you can set or change d attribute for the shape and ports anytime you wish.
var model = new joint.shapes.devs.GenericModel({
attrs: {
'.body': { d: 'M 0 0 0 50 50 50 z'},
'.port-body': { d: 'M 0 0 10 0 10 10 0 10 z'}
}
});
model.attr('.body/d', 'M 25 0 50 50 0 50 z');
JS Fiddle: http://jsfiddle.net/kumilingus/kge023bc/
I'm trying to increment text value everytime I click on the rectangle. What am I doing wrong ?
I don't understand because the call to my var works in drawText but doesn't in setLayer.
I looked at "setLayer" source code, who's working with '+=' syntax, but text is a String var and I don't want to make String concatenation.
value=1
$('canvas').drawText({
name: 'count',
fillStyle: '#0f0',
x: 20, y: 20,
fontSize: 22,
fontFamily: 'Verdana, sans-serif',
text: value
})
.drawRect({
strokeStyle: '#000',
fillStyle: '#ccc',
x: 20, y: 50,
width: 20,
height: 20,
layer: true,
click: function(layer) {
// Spin
$(this).animateLayer(layer, {
rotate: '+=180'
});
v=parseInt(value);
$(this).setLayer('count',{
text: value+1 // TRYING to increment over here
});
}})
Removing and recreating layers will make jCanvas unhappy. A much better solution would be to use setLayer() by parsing the current value to a number, incrementing that value, and passing it to the method:
$('canvas').drawText({
layer: true,
name: 'count',
fillStyle: '#0f0',
x: 20, y: 20,
fontSize: 22,
fontFamily: 'Verdana, sans-serif',
text: '1'
})
.drawRect({
strokeStyle: '#000',
fillStyle: '#ccc',
x: 20, y: 50,
width: 20,
height: 20,
layer: true,
click: function(layer) {
var $canvas = $(this),
countLayer = $canvas.getLayer('count');
// Spin
$canvas.animateLayer(layer, {
rotate: '+=180'
});
$canvas.setLayer(countLayer,{
text: parseFloat(countLayer.text) + 1
});
}
});
I found a workaround removing the layer and creating a new one at the same place.
function updateCount(param) {
$('canvas').removeLayer("count")
.drawText({
name: 'count',
fillStyle: '#0f0',
x: 250, y: 180,
fontSize: 22,
fontFamily: 'Verdana, sans-serif',
text: value,
layer: true,
maxWidth: 200
})
.drawLayers();
}