How to make a path in a custom JointJS element scale? - svg

I have the following custom JointJS element defined:
joint.shapes.webtp.BowTie = joint.dia.Element.define('webtp.BowTie',
{
size: { width: 400, height: 100 },
attrs: {
body: {
strokeWidth: 2,
stroke: '#000000',
fill: '#FFFFFF',
},
},
},
{
markup: [
{
tagName: 'g',
selector: 'g1',
attributes: {
class: 'rotatable',
},
children: [
{
tagName: 'g',
selector: 'g2',
attributes: {
class: 'scalable',
},
children: [
{
tagName: 'path',
selector: 'body',
attributes: {
d: 'm0,0l0,100l200,-25l200,25l0,-100l-200,25l-200,-25',
},
},
]
}
]
},
],
});
Using resize or scale on the shape does not resize it, however. It always ends up being 400x100.
I thought the issue originally was that it needed to be wrapped in a class="scalable" <g> but that didn't fix it either.
I also tried using<line>s instead of <path> but no luck.
Thanks!

The answer is in the refDResetOffset attribute, which (like the other ref custom attributes scales with the parent):
joint.shapes.webtp.BowTie = joint.dia.Element.define('webtp.BowTie',
{
attrs: {
body: {
strokeWidth: 2,
stroke: '#000000',
fill: '#FFFFFF',
refDResetOffset: 'm0,0l0,100l200,-25l200,25l0,-100l-200,25l-200,-25'
},
},
},
{
markup: [
{
tagName: 'g',
selector: 'g1',
attributes: {
class: 'rotatable',
},
children: [
{
tagName: 'g',
selector: 'g2',
attributes: {
class: 'scalable',
},
children: [
{
tagName: 'path',
selector: 'body',
},
]
}
]
},
],
});

Related

JointJS how to create a HTML select (drop down) inside a shape object

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.

High Charts export-server not rending legend LabelFormatter

I have the following code for the node.js high-Charts export-server the legend is showing but the label formatted is not applied and the function is not executed also
I have tried the load function also and it is not working, I tried custom HTML and it is now showing also
let chartDetails = {
type: "png",
options: {
chart: {
type: "pie",
showInLegend: true,
dataLabels: {
enabled: false
}
},
title: {
align: 'left',
floating: false,
text: 'Main Title',
style: {
fontSize: '24px'
}
},
subtitle: {
verticalAlign: 'middle',
align: 'center',
floating: false,
text: '<b>300</b><br>Total Issues',
style: {
fontSize: '30px'
}
},
plotOptions: {
pie: {
innerSize: '70%',
shadow: false,
showInLegend: true,
dataLabels: {
enabled: false,
}
}
},
legend: {
enabled: true,
floating: true,
borderWidth: 0,
align: 'right',
layout: 'vertical',
verticalAlign: 'middle',
useHTML: true,
labelFormatter: function () {
console.log("this: is equal to ");
console.log(this);
return 'custom word';
}
}
,
series: [
{
data: [
{
name: "a",
y: 100
},
{
name: "b",
y: 20
},
{
name: "c",
y: 50
}
]
}
]
}
};
I expected 'custom word' instead 'a','b','c' is showing
It seems when using node-export-server as a module callback functions are not supported. Check this thread on the module github: https://github.com/highcharts/node-export-server/issues/122.
As a workaround, you can use labelFormat property instead of labelFormatter:
legend: {
enabled: true,
floating: true,
borderWidth: 0,
align: 'right',
layout: 'vertical',
verticalAlign: 'middle',
useHTML: true,
labelFormat: "custom word"
}

SideMenu layout example react-native-navigation v2

I need an example with sideMenu react-native-navigation v2. Ideally, I want to navigate from side menu component to other screens (e.g stack with bottom tabs, accounts screen, FAQs screen)
currently this is my layout
Navigation.setRoot({
root: {
sideMenu: {
left: {
component: {
name: 'screen.SideMenu',
}
},
center: {
bottomTabs: {
id: 'tabs',
options: {
topbar: {
visible: true,
}
},
children: [
{
stack: {
id: 'tab1',
children: [
{
component: {
name: 'screen.Home',
options: {
topbar: {
visible: true
},
bottomTab: {
fontSize: 12,
text: 'Home',
icon: homeIcon,
textColor: theme.$tabColor,
selectedTextColor: '#000',
selectedIconColor: '#000',
}
}
},
},
]
}
},
{
stack: {
id: 'tab2',
children: [
{
component: {
name: 'screen.Events',
options: {
bottomTab: {
text: 'Events',
fontSize: 12,
icon: eventsIcon,
textColor: theme.$tabColor,
selectedTextColor: '#000',
selectedIconColor: '#000',
}
}
},
},
]
}
},
],
},
}
}
}
});
In my Side Menu component I am calling this function.
goToAccountsScreen = () => {
console.log(this.props.componentId)
Navigation.push(this.props.componentId, {
component: {
name: 'screen.Accounts',
}
})
}
how do I add the Accounts screen to my layout

get svg code in highchart directive with angular js

in normal highchart i get svg code with code like this
var chart = $('#container').highcharts()
svg = chart.getSVG();
So, how can i get svg code with this highchart directive in angular js???
i try like normal code but i didn't get svg code.
i use this directive for my highchart
https://github.com/rootux/angular-highcharts-directive
and this my code in controller.js
$scope.chartLogisticGIGR = {
options: {
tooltip: {
shared: true
}
},
xAxis: { // Primary xAxis
categories: $scope.nameMonths,
title: {
text: 'Month'
},
labels: {
enabled: true
},
min:0
},
yAxis: [{ // Primary yAxis
title: {
text: 'GI / GR in IDR'
},
labels: {
formatter: function () {
return Highcharts.numberFormat(this.value / 1000000,'0') + ' mil';
}
}
}, { // Secondary yAxis
title: {
text: 'Balance'
},
labels: {
formatter: function () {
return Highcharts.numberFormat(this.value / 1000000,'0') + ' mil';
}
},
}],
series: [{
name: 'AGP - Goods Receipt',
type: 'column',
stacking: 'normal',
stack: '1',
data: $scope.dataLogisticGIGR_AGP_GR,
color: $rootScope.getColor('AGP Ext'),
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}: {point.y:,.0f}</span><br/>'
}
},{
name: 'AGP - Goods Issue',
type: 'column',
stacking: 'normal',
stack: '1',
data: $scope.dataLogisticGIGR_AGP_GI,
color: $rootScope.getColor('AGP Int'),
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}: {point.y:,.0f}</span><br/>'
}
},{
name: 'AGP - Balance',
type: 'spline',
data: $scope.dataLogisticGIGR_AGP_Balance,
color: $rootScope.getColor('AI 2'),
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}: {point.y:,.0f}</span><br/>'
}
},{
name: 'AI - Goods Receipt',
type: 'column',
stacking: 'normal',
stack: '3',
data: $scope.dataLogisticGIGR_AI_GR,
color: $rootScope.getColor('AI'),
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}: {point.y:,.0f}</span><br/>'
}
},{
name: 'AI - Goods Issue',
type: 'column',
stacking: 'normal',
stack: '3',
data: $scope.dataLogisticGIGR_AI_GI,
color: $rootScope.getColor('AP 2'),
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}: {point.y:,.0f}</span><br/>'
}
},{
name: 'AI - Balance',
type: 'spline',
data: $scope.dataLogisticGIGR_AI_Balance,
color: $rootScope.getColor('AP'),
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}: {point.y:,.0f}</span><br/>'
}
}],
title: {
text: ''
},
loading: false
};
in this is my code in directive highchart
'use strict';
angular.module('chartsExample.directives',[])
.directive('chart', function () {
return {
restrict: 'E',
template: '<div></div>',
scope: {
chartData: "=value"
},
transclude:true,
replace: true,
link: function (scope, element, attrs) {
var chartsDefaults = {
chart: {
renderTo: element[0],
type: attrs.type || null,
height: attrs.height || null,
width: attrs.width || null
}
};
//Update when charts data changes
scope.$watch(function() { return scope.chartData; }, function(value) {
if(!value) return;
// We need deep copy in order to NOT override original chart object.
// This allows us to override chart data member and still the keep
// our original renderTo will be the same
var newSettings = {};
angular.extend(newSettings, chartsDefaults, scope.chartData);
var chart = new Highcharts.Chart(newSettings);
});
}
};
});
Thank's....

Dynamically Building a Container with this.setItems()

I'm trying to build my container in the initialize() function by creating all my components then calling this.setItems([...]). For some reason, my components are being placed on top of each other, rather than after each other in the vbox.
I am able to grab the top component and move it down, as is shown in the attached image.
Simplified view with two components:
Ext.define("Sencha.view.DynamicView", {
extend: 'Ext.Container',
xtype: 'dynamic-view',
requires: [],
config: {
layout: {
type: 'vbox'
},
flex: 1,
cls: 'view-container',
store: null
},
createRadioSet: function() {
this.radioFieldSet = Ext.create('Ext.form.FormPanel', {
flex: 1,
items: [{
xtype: 'fieldset',
title: 'About You',
defaults: {
xtype: 'radiofield',
labelWidth: '40%'
},
instructions: 'Favorite color?',
items: [{
name: 'color',
value: 'red',
label: 'Red'
},
{
name: 'color',
value: 'green',
label: 'Green'
}
]
}]
});
return this.radioFieldSet;
},
createCheckboxSet: function() {
this.checkboxFieldSet = Ext.create('Ext.form.FormPanel', {
flex: 1,
items: [{
xtype: 'fieldset',
title: 'Check all that apply',
defaults: {
xtype: 'checkboxfield',
labelWidth: '40%'
},
instructions: 'Tell us all about yourself',
items: [{
name: 'firstName',
value: 'First',
label: 'First Name'
},
{
name: 'lastName',
value: 'Last',
label: 'Last Name'
}
]
}]
});
return this.checkboxFieldSet;
},
initialize: function() {
this.callParent(arguments); // #TDeBailleul - fixed
var r1 = this.createRadioSet();
var cbSet1 = this.createCheckboxSet();
// this.add(cbSet1);
// this.add(r1);
this.setItems([r1, cbSet1]);
}
});
My problem was that I was adding my components incorrectly in a tab controller. I'm including an example that creates buttons on one tab and the checkboxes on another tab.
Ext.Loader.setConfig({
enabled : true
});
Ext.application({
name : ('SF' || 'SenchaFiddle'),
createRadioSet: function () {
this.radioFieldSet = Ext.create('Ext.form.FormPanel', {
height: '300px',
width: '300px',
items: [
{
xtype: 'fieldset',
title: 'Title',
defaults: {
xtype: 'radiofield',
labelWidth: '40%'
},
instructions: 'Favorite color?',
items: [
{
name: 'color',
value: 'red',
label: 'Red'
},
{
name: 'color',
value: 'green',
label: 'Green'
}
]
}
]
});
return this.radioFieldSet;
},
createButton: function(i) {
return Ext.create('Ext.Button', {
text: 'hello' + i,
height: '50px',
width: '100px'
});
},
launch: function () {
var tabPanel = Ext.create('Ext.tab.Panel', {
layout: 'card',
padding: 2,
tabBarPosition: 'bottom',
items: [
{
id: 'tab1',
title: 'Home',
layout: 'hbox',
xtype: 'container',
iconCls: 'home'
},
{
id: 'tab2',
title: 'More',
layout: 'hbox',
xtype: 'container',
iconCls: 'star'
}
]
});
Ext.Viewport.add(tabPanel);
var a,b;
for (var i = 0; i < 3; i++) {
a = this.createButton(i);
b = this.createRadioSet();
// tabPanel.getAt(0).add(b); // Reference the proper component: Tab 1
Ext.getCmp('tab1').add(a);
Ext.getCmp('tab2').add(b);
}
}
});

Resources