Related
I am looking for best practises or advice in how to create interactive elements within Shapes (elements) using the JointJS (Rappid) library.
This is what I have done currently:
The code
const shape = new joint.shapes.basic.Generic({
type: 'shape',
attrs: {},
markup: [
{
tagName: 'foreignObject',
selector: 'foreignObject',
attributes: {
x: '10',
y: '10',
width: '60',
height: '100',
},
children: [
{
tagName: 'div',
namespaceURI: 'http://www.w3.org/1999/xhtml',
selector: 'content',
style: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
},
children: [
{
tagName: 'select',
selector: 'select',
style: {
'z-index': 1,
},
children: [
{
tagName: 'option',
value: 'test1',
textContent: 'test 1',
},
{
tagName: 'option',
value: 'test2',
textContent: 'test 2',
},
],
},
],
},
],
},
],
});
You can see there is a shape rendered and it has a select element in it by using a foreignObject (https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject).
However, using foreignObject is troublesome due to that they do not play well in browsers and the drop down you see here doesn't actually work.
I could start hacking around and get it to work but this is the point of the question, is there a cleaner way in achieving this?
I need something like this
https://resources.jointjs.com/tutorial/html-elements
But the html library is now decrepitated and JointJS wants you to use markup JSON instead.
Lastly, I have seen this post which doesn't fill me much with confidence...
https://groups.google.com/g/jointjs/c/-yXXlnreq6M
But I am hoping as this is from 5 years ago, it is outdated and we don't need to have to do the workarounds as it suggests?
HTML can be added inside foreignObject, but as you mentioned there can be some issues in browsers. One example of using foreignObject can be found here.
The code demonstrates how to create a text input with foreignObject.
var paper = new joint.dia.Paper({
el: document.getElementById('paper'),
width: 650,
height: 400,
gridSize: 10,
model: graph,
guard: function(evt) {
return evt.target instanceof HTMLInputElement;
}
});
paper.on('blank:pointerdown cell:pointerdown', function() {
document.activeElement.blur();
});
var Example = joint.dia.Element.define('example.ForeignObject', {
attrs: {
body: {
refWidth: '100%',
refHeight: '100%',
stroke: '#333333',
fill: '#ffffff',
strokeWidth: 2
},
foreignObject: {
refWidth: '100%',
refHeight: '100%'
}
}
}, {
markup: [{
tagName: 'rect',
selector: 'body'
}, {
tagName: 'foreignObject',
selector: 'foreignObject',
attributes: {
'overflow': 'hidden'
},
children: [{
tagName: 'div',
namespaceURI: 'http://www.w3.org/1999/xhtml',
selector: 'content',
style: {
fontSize: 14,
width: '100%',
height: '100%',
position: 'static',
backgroundColor: 'transparent',
textAlign: 'center',
margin: 0,
padding: '0px 10px',
boxSizing: 'border-box',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
},
children: [{
tagName: 'span',
textContent: 'First Name'
}, {
tagName: 'input',
selector: 'firstname',
attributes: {
'type': 'input',
'name': 'firstname'
},
style: {
position: 'static',
width: '100%'
}
}, {
tagName: 'span',
textContent: 'Last Name'
}, {
tagName: 'input',
selector: 'lastname',
attributes: {
'type': 'input',
'name': 'lastname'
},
style: {
position: 'static',
width: '100%'
}
}]
}]
}]
}, {
attributes: {
value: {
set: function(text, _, node) {
if ('value' in node) node.value = text;
}
}
}
});
joint.shapes.example.ForeignObjectView = joint.dia.ElementView.extend({
events: {
'change input': 'onInputChange'
},
onInputChange: function(evt) {
var input = evt.target;
this.model.attr(input.name + '/value', input.value);
}
});
The article that you linked is deprecated, but there is an updated version of creating elements with a HTML face here. You can see some select fields demonstrated there, but it is a little more involved.
I dont know what to do...
Without hbox the grid appears,
but with hbox not.
I added with & height and flex to each child element,
but it doesnt work...
Thanks in advance!
And here's the code:
Ext.onReady(function() {
var myStore = Ext.create('Ext.data.SimpleStore', {
fields: [ 'bMin', ], });
var myData = [ { "bMin": 10, } ];
myStore.loadData(myData);
var grid = new Ext.grid.GridPanel({
layout : { type : 'hbox', align : 'stretch', flex:2,
Height: 150,
Width: 300,
},
cls: 'custom-grid',
store: myStore,
columns: [
{text: "bMin", dataIndex: 'bMin', type: 'float',},
],
viewConfig: {
emptyText: 'No records',
forceFit : true,
},
renderTo: Ext.getBody(),
});
var myPanel = new Ext.Panel({
layout : {
type : 'hbox',
align : 'stretch',
},
title: 'Hello',
minHeight : 150,
minWidth: 300,
Height: 150,
Width: 300,
items: [
grid,
{xtype: 'button', width: 50, height: 50, flex: 1}
],
renderTo: Ext.getBody()
});
});
On the Grid you don't need a 'layout' config, also when using an HBox Height and Width is ignored on the child components so using flex is the way to go. I also added a 'pack' attribute to the hbox layout.
Try this:
Ext.onReady(function() {
var myStore = Ext.create('Ext.data.SimpleStore', {
fields: [ 'bMin', ], });
var myData = [ { "bMin": 10, } ];
myStore.loadData(myData);
var grid = new Ext.grid.GridPanel({
flex: 1,
cls: 'custom-grid',
store: myStore,
columns: [
{text: "bMin", dataIndex: 'bMin', type: 'float',},
],
viewConfig: {
emptyText: 'No records',
forceFit : true,
},
renderTo: Ext.getBody(),
});
var myPanel = new Ext.Panel({
layout : {
type : 'hbox',
align : 'stretch',
pack: 'start'
},
title: 'Hello',
minHeight : 150,
minWidth: 300,
Height: 150,
Width: 300,
items: [
grid,
{xtype: 'button', flex: 1, text: 'test'}
],
renderTo: Ext.getBody()
});
});
JSFiddle Example:
http://jsfiddle.net/vzURb/2/
I see a number of problems here...
height and width config properties should not be capitalized
The flex, height, and width properties should all be on the panel itself, NOT on the panel's layout
The flex attribute will be weighted, so using flex: 1 on your button and flex: 2 on your panel will almost certainly not be what you are looking to do
You have renderTo on the grid, which is supposed to be inside your panel, so it should not use this config
You have commas at the ends of property lists, this can lead to lots of problems
You have type on a column, which is not a valid config
You don't need the layout on the grid
I can't tell exactly what it is that you want to do, but having an hbox layout with a button as the second item will look quite strange. But, if that is what you are intending, this is probably more what you want:
var grid = new Ext.grid.GridPanel({
cls: 'custom-grid',
store: myStore,
columns: [
{text: "bMin", dataIndex: 'bMin'}
],
viewConfig: {
emptyText: 'No records',
forceFit : true
}
});
var myPanel = new Ext.Panel({
layout : {
type : 'hbox',
align : 'stretch'
},
title: 'Hello',
height: 150,
width: 300,
items: [
grid,
{xtype: 'button', width: 50, height: 50, flex: 1}
],
renderTo: Ext.getBody()
});
I need to put 3 elements under each other in the center of page. It is not a problem with HBOX. But my elements have different width:
two elements with 350 width and one element with 1000 width. here is the sample:
Ext.create('Ext.Viewport', {
layout: {
type: "hbox",
pack: "center",
align: "middle"
},
items: {
xtype: 'container',
items:[{
xtype: 'image',
height: 350,
width: 350,
src: '/images/logo.jpg'
},{
xtype: 'image',
height: 350,
width: 350,
src: '/images/logo2.jpg'
},{
xtype: 'panel',
width: 1000,
margin: '0px 0px 0px -325px',
frame: true,
autoscroll: true,
title: 'panel title',
html: 'some panel with some rows with<br /> some text'
}]
},
renderTo: Ext.getBody()
});
The main problem is horisontal alignment of elements.
The second problem is: no scrollbar if the resolution of the screen is small and I have big text in panel.
Ok, another example:
Ext.create('Ext.Viewport', {
layout: {
type: "hbox",
pack: "center",
align: "middle"
},
items: {
xtype: 'container',
items:[{
xtype: 'form',
width: 350,
title: 'Form Panel',
items: [{
xtype: 'textfield',
fieldLabel: 'Name'
}]
},{
xtype: 'panel',
width: 1000,
frame: true,
autoscroll: true,
title: 'panel title',
html: 'some panel with some rows with<br /> some text'
}]
},
renderTo: Ext.getBody()
});
This panel will be exactly in the middle of screen, but the form will not.
P.S. I've tried to move layout to the container - it doesn't work
Ext.create('Ext.Viewport', {
layout : 'fit',
autoScroll : true,
items: {
xtype: 'container',
autoScroll : true,
minHeight : 1000,
layout: {
type: "vbox",
pack: "center",
align: "center"
},
items:[{
xtype: 'image',
height: 350,
width: 350,
src: '/images/logo.jpg'
},{
xtype: 'image',
height: 350,
width: 350,
src: '/images/logo.jpg'
},{
xtype: 'panel',
width: 1000,
margin: '0px 0px 0px -325px',
frame: true,
title: 'panel title',
html: 'some panel with some rows with<br /> some text'
}]
},
renderTo: Ext.getBody()
});
I think that maybe you should define a minHeight to the container, and include the layout 'fit' to the container in order to get the autoscroll panel.
And include the vbox layout to the contianer' items.
First of all move your layout definition inside container. It has nothing to do with viewport. Second for your layout I think you should use
type: 'vbox',
align: 'center',
pack: 'center',
I also think there might be something with the way ExtJs layouts images - because when I tried your example in jsfiddle - images still won't layout in vbox, but other components - (box or button) would layout jsut fine
i have the problem with displaying fields on form
var test = Ext.create('Ext.form.Panel', {
renderTo: 'test',
title: '1. zzzz',
width: 800,
bodyPadding: 5,
defaults: {
anchor: '100%'
},
items: [
{
xtype: 'fieldset',
defaults: {
anchor: '100%'
},
layout: 'column',
items: [
{
xtype: 'panel',
fieldDefaults: {
msgTarget: 'side',
labelWidth: 75
},
columnWidth: .5,
flex: 1,
defaultType: 'textfield',
defaults: {
anchor: '100%',
flex: 1
},
items: [
{
xtype: 'numberfield',
hideTrigger: true,
fieldLabel: 'zzzz',
//anchor: '100%',
//anchor: '-5',
name: 'SRD_NUMBER'
},
{
fieldLabel: 'zzzz',
//anchor: '-5',
name: 'SRD_NAME_BR'
},
{
fieldLabel: 'zzzzz',
//anchor: '-5',
name: 'SRD_NAME_FL'
},
{
xtype: 'numberfield',
hideTrigger: true,
fieldLabel: 'zzzz',
disabled: true,
//anchor: '-5',
name: 'SRD_FOP'
},
{
fieldLabel: 'zzzz',
//anchor: '-5',
name: 'SRD_NAME_ORDER'
},
{
xtype: 'panel',
id: 'dep-img',
border: false,
height: 50,
width: 100,
cls: 'x-form-item',
html: '<img src="http://dep-image/id/10000001482" width="100" height="50" title="zzz">'
},
{
xtype: 'filefield',
name: 'file1',
msgTarget: 'side',
border: 3,
//anchor: '100%',
fieldLabel: 'zzzz',
buttonText: 'zzzzzz'
},
{
fieldLabel: 'zzz',
//anchor: '-5',
name: 'company'
},
{
fieldLabel: 'zzzz',
//anchor: '-5',
name: 'company'
}]
}
]
} //fieldset
]//glob
});
i need to fit fields width to column width.
on this page http://docs.sencha.com/ext-js/4-0/#/api/Ext.form.FieldContainer 2 examples
and in second example they set defaults {layout: '100%'} and it looks like it does not work.
found own salvation: by adding layout: 'fit' or layout: 'anchor' to fieldset anchor
defaults: {
layout: 'fit',
flex: 1
},
thanks to all
You must set height property to your form and if it still is not displaying then give height to fieldset too.
found own salvation: by adding layout: 'fit' or layout: 'anchor' to fieldset anchor
defaults: {
layout: 'fit',
flex: 1
},
thanks to all
I would specify layout:'fit' on the formPanel since you are using a single fieldset.
The rest i dont understand. It looks like you specify column layout but using just one column.
Could you clean up the example and i would be happy to help.
After a quick look... Have you tried putting anchor: '0' on both fields and containers?
Also, you should use fieldDefaults instead of
defaults: {
anchor: '100%',
flex: 1
},
I need to create an advanced, fluid Border layout for our Report system.
The West pane would be split into 2 separate panes, top for the filter form, and the bottom for navigation.
The Center pane would be split into 3 separate panes, top for the primary data grid, and 2 bottom panes for sub report grids. I may at some point need 3 bottom panes, but I'm hoping to avoid that.
Here is an example of what I am looking for: http://dl.dropbox.com/u/298258/Amistaff/desiredLayout.png
What I have so far is definitely less than satisfactory.
http://dl.dropbox.com/u/298258/Amistaff/currentLayout.png
Here is the code:
var ReportForm = new Ext.FormPanel({
url: '',
frame: false,
border: false,
title: 'Filter Results',
width: 260,
labelWidth: 50,
padding: '10 0 0 5',
standardSubmit: true,
items: [
{
fieldLabel: 'Client',
hiddenName: 'ClientID',
mode: 'local',
store: frmClientStore,
displayField: 'CompanyName',
valueField: 'ClientID',
width: 150,
editable: true,
triggerAction: 'all',
xtype: 'combo'
}
],
buttons: [
{text:'Export',handler:function(){}},
{text:'Search',handler:function(){}},
{text:'Reset',handler:function(){}}
]
});
var ReportGrid = new Ext.grid.GridPanel({
id: 'ReportGrid',
width: '100%',
height: '50%',
viewConfig: {
forceFit: true
},
autoHeight: true,
loadMask: true,
stripeRows: true,
store: ReportStore,
margins: '5 5 5 5',
cm: ReportColumnModel
,bbar: new Ext.PagingToolbar
(
{
pageSize: 10,
store: ReportStore,
displayInfo: true,
displayMsg: 'Displaying results {0} - {1} of {2}'
}
)
});
var viewport = new Ext.Viewport({
layout: 'border',
items: [
{
region: 'west',
layout: 'vbox',
layoutConfig: {
align: 'stretch'
},
width: 260,
minSize: 175,
maxSize: 400,
margins: '5 5 5 5',
items: [
ReportForm,
{
region: 'south',
title: 'Superuser',
border: false,
xtype: 'tabpanel',
activeTab: 0,
items: [
{
title: 'General',
xtype: 'panel',
height: 200,
html: '',
},
{
title: 'Exams',
height: 200,
html: ''
}
]
}
]
},
new Ext.Panel({
region: 'center',
deferredRender: false,
layout: 'fit',
margins: '5 5 5 0',
items: [
ReportGrid,
new Ext.Panel({
region: 'south',
border: false,
height: '50%',
html: 'foo',
layout: 'fit',
items: [
new Ext.Panel({
region: 'west',
width: '50%',
border: false,
html: 'West'
}),
new Ext.Panel({
region: 'east',
width: '50%',
border: false,
html: 'East'
})
]
})
]
})
]
});
Thanks...
EDIT:
Many thanks to amol for the answer below. I have one additional question. If I collapse the form in the west region, how do I make it resize the navigation panel to fill the remaining space?
code -
var ReportForm = new Ext.FormPanel({
url: '',
frame: false,
border: false,
title: 'Filter Results',
width: 260,
labelWidth: 50,
padding: '10 0 0 5',
standardSubmit: true,
items: [
{
fieldLabel: 'Client',
hiddenName: 'ClientID',
mode: 'local',
//store: frmClientStore,
displayField: 'CompanyName',
valueField: 'ClientID',
width: 150,
editable: true,
triggerAction: 'all',
xtype: 'combo'
}
],
buttons: [
{text:'Export',handler:function(){}},
{text:'Search',handler:function(){}},
{text:'Reset',handler:function(){}}
]
});
var ReportGrid = new Ext.grid.GridPanel({
id: 'ReportGrid',
flex:1,
viewConfig: {
forceFit: true
},
loadMask: true,
stripeRows: true,
//store: ReportStore,
margins: '5 5 5 5',
cm: new Ext.grid.ColumnModel({
columns:[
{header:'A column', dataIndex:'afield'},
{header:'B column', dataIndex:'bfield'}
]
}),
store:new Ext.data.ArrayStore({
autoLoad:true,
fields:['afield', 'bfield'],
data:[['value 1','value 3'],['value 2', 'value4']]
}),
bbar: new Ext.PagingToolbar
(
{
pageSize: 10,
//store: ReportStore,
displayInfo: true,
displayMsg: 'Displaying results {0} - {1} of {2}'
}
)
});
var viewport = new Ext.Viewport({
layout: 'border',
items: [
{
region: 'west',
layout: 'vbox',
layoutConfig: {
align: 'stretch'
},
width: 260,
minSize: 175,
maxSize: 400,
margins: '5 5 5 5',
items: [
ReportForm,
{
region: 'south',
title: 'Superuser',
border: false,
xtype: 'tabpanel',
activeTab: 0,
items: [
{
title: 'General',
xtype: 'panel',
height: 200,
html: ''
},
{
title: 'Exams',
height: 200,
html: ''
}
]
}
]
},
new Ext.Panel({
region: 'center',
deferredRender: false,
layout: 'vbox',
layoutConfig:{align:'stretch'},
margins: '5 5 5 0',
items: [
ReportGrid,
{
border: false,
flex:1,
layout: 'hbox',
layoutConfig:{align:'stretch'},
defaults:{flex:1},
items: [
new Ext.Panel({
html: 'West'
}),
new Ext.Panel({
html: 'East'
})
]
}
]
})
]
});