JointJS: How can you create a oneSide link with 2 different sides - jointjs

I am trying to create a link that links from one shape with a fixed side to another with a different fixed side. Is this possible?
link.router('oneSide', {
side: 'top',
padding: 30
});
https://resources.jointjs.com/docs/jointjs/v3.1/joint.html#routers.oneSide

I'm not sure 'oneSide' should even be in the routers because in the documentation the router only defines the middle points of the path not the start and end.
In either case, the router function must return an array of route points that the link should go through (not including the start/end connection points). The function is expected to have the form function(vertices, args, linkView)
I found out that in defining the links you can specify the anchor which is basically the start and end point. For the shapes there some built-in anchors. We have to use 'left' and 'right' for this case.
Here is my code. It's in TypeScript but I'm sure you can convert it to JS easily if you need to.
makeLink(parentElementLabel, childElementLabel) {
return new joint.shapes.standard.Link({
source: {
id: parentElementLabel,
anchor: {
name: 'right'
}
},
target: {
id: childElementLabel,
anchor: {
name: 'left'
}
},
router: {
name: 'normal'
},
attrs: {
line: {
stroke: 'black',
cursor: 'default',
},
wrapper: {
cursor: 'default'
}
},
// smooth: true,
});
}

Related

Dynamic options.addFields in beforeConstruct not working

I was looking at creating a simple generic reusable text-only widget in apostrophe-cms so I made the module text-only-widgets.
with the following code
In lib/modules/text-only-widgets/index.js
module.exports = {
extend: 'apostrophe-widgets',
label: 'Section Heading',
beforeConstruct: function (self, options) {
console.log('options.addFields : ', options.addFields)
options.addFields = [
{
name: 'sectionHeading',
label: 'Section Heading',
type: 'string'
}
].concat(options.addFields || [])
}
};
In lib/modules/text-only-widgets/views/widget.html
{{ data.widget.sectionHeading }}
Now I tried using the above widget in one of my pages as below:
<div>
{{
apos.area(data.page, 'aboutUsDescriptionTwo', {
widgets: {
'text-only': {
addFields: [
{
name: 'sectionDescription', // set these fields dynamically
label: 'Section Description', // set these fields dynamically
type: 'string'
}
]
}
}
})
}}
</div>
As shown in the below image, notice even after passing the addFields with label as Section Description to the text-only widget doesn't override the defaults set in the index.js.
I tried console.log on the options.addFields in index.js but it logs undefined as show below, I also tried few different variations but none works.
The addFields option is at the module level, it controls what fields exist for all instances of this widget. It is not an option that can be passed to individual instances of the widget via apos.area. Thus you can't do it in this way.
The correct approach is to create a second module which uses extend to extend the first one and addFields, at the module level, to add the additional field. Then, in your area, you can offer just one of the two widget types, or both, as is appropriate to your needs.
Thus in addition to lib/modules/text-only-widgets/index.js you would also have:
// in lib/modules/text-plus-description-widgets/index.js
module.exports = {
extend: 'text-only-widgets',
label: 'Section Heading and Description',
addFields: [
{
name: 'sectionDescription',
label: 'Section Description',
type: 'string'
}
]
};
And this widget would also have its own widget.html.

Highcharts - Hide child labels in a multiple levels and multiple layouts treemap

On highcharts, I have a treemap with 2 levels, each with a different layout algorithm. Now I want to limit what we can see to the current level. It means that on level 1, I don't want to see the labels of level 2, which would only appear when drilling down (and the labels of level 1 would disappear).
I know it is easy with levelIsConstant: false, but this only works with 1 level, and I use 2 because I need different layouts.
Here is the link to what I currently have:
series: [{
type: "treemap",
allowDrillToNode: true,
alternateStartingDirection: true,
levels: [{
level: 1,
layoutAlgorithm: 'squarified',
dataLabels: {
enabled: true,
align: 'left',
verticalAlign: 'top',
style: {
fontSize: '15px',
fontWeight: 'bold'
}
}
}, {
level: 2,
layoutAlgorithm: 'stripes',
color: 'blue'
}],
//...
http://jsfiddle.net/dhfera2y/2/
I want all the names to be hidden, as well as the lines separating them.
EDIT: Using a rgba color on each level, I can hide the nodes below it, but I still cannot hide their label!
Thank you it is a smart idea for the labels issue, but as I say I cannot use levelIsConstant: false because I need a different layout for each level at every moment. With this solution both levels can have a different layout when I am on the top level, but I soon as I drill down I loose the correct layout for the new view.
Almost :-)
EDIT : Okay so I finally managed to do it. I think it is impossible to achieve this in the way I was trying to, which was using the parent option for each child point of the serie in order to determine the hierarchy of the tree. So instead of using one serie with a hierarchy, I use one serie for the top level which I link to several series for the level below.
I was able the do this thanks to the drilldown option.
I found the solution in the official documentation :
http://www.highcharts.com/docs/chart-concepts/drilldown
I adjusted the code and it was all right. Here is the solution I came up with (it is a different work from my first link) :
http://jsfiddle.net/ff964fog/47/
series: [{
type: 'treemap',
layoutAlgorithm: 'squarified',
borderWidth: 3,
data: modulesData
}],
drilldown: {
series: servicesSerie
},
I still have to adjust a few things (like the disappearance of the animations for the bottom level), but in the end I have exactly what I wanted !
My take on some settings you can use to achieve this (JSFiddle):
series: [{
type: "treemap",
allowDrillToNode: true,
levelIsConstant: false,
// ...
levels: [{
level: 1,
dataLabels: {
enabled: true
}
// ...
}, {
level: 2,
borderWidth: 0,
dataLabels: {
enabled: false
}
}],
data[{
//...
}]
}]
The level 2 settings apply only when viewing from level 1. When drilling down the new view is considered to be level 1 because of levelIsConstant: false.
Setting borderWidth: 0 in level 2 is only needed if you want to hide the grid of level 2 when viewing from level 1.
You can use a custom formatter for plotOptions.treemap.datalabels. The code bellow is an example that uses this.series.rootNode and this.point.parent and compare them to examine if the label should be shown or not:
plotOptions: {
treemap: {
dataLabels: {
formatter: function(data) {
if (this.point.parent == (this.series.rootNode || null)) {
return this.key;
}
}
}
}
}
You can use any other property that is available in formatter function. Just log (console.log) this and data in the formatter function to see all the properties available:
plotOptions: {
treemap: {
dataLabels: {
formatter: function(data) {
console.log(this, data);
}
}
}
}

I can not get the value of a text field in extJS

Faced with a problem at work with ExtJS
There is such a code - a new class (view)
Ext.define('FormApp.view.ElementContainer', {
extend: 'Ext.Container',
alias: 'widget.elemcontainer',
initComponent: function() {
this.items = [{
layout: {
type: 'hbox',
align: 'middle'
},
items: [
{ xtype: 'component',
html: '&nbspПоиск&nbsp&nbsp'},
{ xtype: 'textfield',
width: 495,
name: 'search'
},
{ xtype:'component',
html:'&nbsp&nbsp'},
{ xtype: 'button',
text: 'Найти',
width: 80,
action: 'searchTreeData'}
]}
];
this.callParent();
}
});
Then in the controller I write code like this to get the value of the textfield
Ext.define('FormApp.controller.ControlOne', {
extend: 'Ext.app.Controller',
views: ['ElementContainer', 'TreeView'],
init: function() {
this.control({
'elemcontainer button[action=searchTreeData]': {
click: this.searchTree
},
'elemcontainer textfield[name=search]':{change: this.str}
});
},
searchTree: function(searchStr) {
var dat = Ext.widget('elemcontainer');
var str = dat.down('textfield').getValue();
alert (str.getValue());
},
str: function()
{alert('OK');}
});
I can not get the value of a text field in extJS
How to access the elements to get their values​​?
Thanks in advance and sorry for my clumsy English
The problem is that by using Ext.widget(...) in searchTree(), you're creating a new instance of the class (be sure to check the docs), rather than getting the of the component that already exists.
Another issue is that str is already the "value" of the textfield, so calling getValue() on str.getValue() won't get you very far either.
So a few suggestions:
Update you searchTree method to pass the correct arguments. Since this method is getting called on the click event of a button, the arguments will be those of the click event for Ext.button.Button : searchTree( btn, e, opts ) {...}
Once you have the correct arguments being passed to searchTree(), you can then use the component selector methods to get the existing instance of the container. For example, since the button is already a descendant of the container, you can do the following to get the correct instance of the component:
var ctr = btn.up( "elemcontainer" )
And now that you have the correct instance of the container, you can again use one of the component selector methods to find the textfield:
var str = ctr.down( 'textfield' ).getValue()

extjs4 MVC Scope Issue

I am trying to call resetCombo method once i click on link from tooltip which is rendered on combo
But i am not able to access it because of scope issue not sure what i am missing. Please help me on this.
Ext.define('test.BasicForm', {
extend: 'Ext.form.Panel',
renderTo:Ext.getBody(),
initComponent :function(){
this.items=[
{
fieldLabel: 'Test',
xtype: 'combo',
displayField: 'name',
width: 320,
labelWidth: 130,
store: [
[1, 'Value 1'],
[2, 'Value 2'],
[3, 'Value 3'],
[4, 'Value 4']
],
listeners:{
afterrender: function(combo) {
Ext.create('Ext.tip.ToolTip', {
target: combo.getEl(),
autoHide: false,
name:'tool-tip',
scope:this,
html: 'Old value was '+ combo.getValue()+ ' test',
listeners: {
beforeshow: function() {
return combo.isDirty();
}
}
});
}
},
value:'1'
}];
this.callParent(arguments);
},
resetCombo:function(){
alert('called');
}
});
First this has nothing to do with ExtJS4's MVC features which are generally associated with a controller's control method:
http://docs.sencha.com/ext-js/4-1/#!/api/Ext.app.Controller-method-control
Second, you may be able to instead get the effect you want by switching to the following, fully qualified path to reset combo:
onclick="javascript:test.BasicForm.resetCombo();" //etcetera
Lastly, though you may get the above to work, it is far from best practice. I don't have time to give the complete answer, but essentially what you want to do consists of:
Adding a click event handler to the tooltip's underlying Element
Then inside the element use the arguments to Ext.dom.Element.click (see http://docs.sencha.com/ext-js/4-1/#!/api/Ext.dom.Element-event-click) to ensure it was an <A> tag that got clicked
Then invoke the desired function without having to use Javascript pseudo-URL's and a fully qualified path to the function
Here is my working re-write of the afterrender listener following the above guidelines, with some tweaks to scope, in particular storing a reference to the form in a variable of the same name.
listeners:{
afterrender: function(combo) {
var form = this;
var tooltip = Ext.create('Ext.tip.ToolTip', {
target: combo.getEl(),
autoHide: false,
name:'tool-tip',
html: 'Old value was '+ combo.getValue()+ ' <a class="tooltipHref" href="#">test</a>',
listeners: {
beforeshow: function() {
return combo.isDirty();
},
afterrender: function() {
tooltip.el.on('click', function(event, element) {
if (element.className == 'tooltipHref') {
form.resetCombo();
}
});
}
}
});
},
scope: this
}
test
this code is attempting to call a function named resetCombo which is stored inside the top-level object (the window object).

Ext Js : add nested panels dynamically

I have several records of the same type that I want to show on the screen. I thought about creating several panels that will print the data of each record. I chose this solution because data structure is too complex to be printed in a simple grid. Here is a simplified example of that structure :
{
label: 'myLabel',
{
attr1: 'value1',
attr2: 'value2'
}
startValidityDate: oneDay,
endValidityDate: anotherDay
}
I try to add dynamically nested panels in my current panel :
var myStore = new Ext.data.Store({
id: 'myStore',
restful: true,
idProperty: 'OID',
root: 'tbas',
proxy: myProxy,
reader: myReader,
autoLoad: false,
listeners: {
'load': function(data){
var records = data.getRange();
var currStore = null;
for(var i=0; i<records.length; i++) {
currStore = new Ext.Panel({
layout:'vBox',
items: [{
xtype: 'textfield',
fieldLabel: I18nManager.get('label_ttbaUI_label'),
name: 'tbaLabel',
value: records[i].data.tbaLabel
},{
xtype: 'textfield',
fieldLabel: I18nManager.get('label_ttbaUI_label'),
name: 'tbaOid',
value: records[i].data.tbaoid
}]
});
recordList.add(currStore);
console.log("------------------------------");
console.log(currStore);
}
recordList.doLayout();
}
}
});
var recordList = new Ext.Panel({
id: 'recordList',
renderTo: 'recordPart',
layout:'vBox',
title: I18nManager.get('label_ttbaUI_selected_tariffs')
});
recordList.doLayout();
In the firebug console, the UI objects seems to be ok.
My problem is that the recordList elements are not visible
I can see that they exist in the FB console, but they are not well printed on the screen.
Did I forgot something that make the elements hidden ? or bad printed ?
I'm sure that it is a CSS problem, some trouble with ext-all.css : when I remove the content of that CSS, I can see my fields
There must be something wrong in the way I wrote the code so that it causes the render problem WDYT ???

Resources