From 1d05e161c9895c747953a7e68cadfe4ed431b200 Mon Sep 17 00:00:00 2001 From: Junsik Shim Date: Mon, 19 Apr 2021 21:56:58 +0900 Subject: [PATCH] - Add css support in storybook. - Add icons to mxgraph. - Convert some examples to storybook. --- package-lock.json | 81 ++++-- package.json | 3 +- packages/core/css/common.css | 166 +++++++++++ packages/core/images/button.gif | Bin 0 -> 137 bytes packages/core/images/close.gif | Bin 0 -> 70 bytes packages/core/images/collapsed.gif | Bin 0 -> 877 bytes packages/core/images/error.gif | Bin 0 -> 907 bytes packages/core/images/expanded.gif | Bin 0 -> 878 bytes packages/core/images/maximize.gif | Bin 0 -> 843 bytes packages/core/images/minimize.gif | Bin 0 -> 64 bytes packages/core/images/normalize.gif | Bin 0 -> 845 bytes packages/core/images/point.gif | Bin 0 -> 55 bytes packages/core/images/resize.gif | Bin 0 -> 74 bytes packages/core/images/separator.gif | Bin 0 -> 146 bytes packages/core/images/submenu.gif | Bin 0 -> 56 bytes packages/core/images/transparent.gif | Bin 0 -> 90 bytes packages/core/images/warning.gif | Bin 0 -> 276 bytes packages/core/images/warning.png | Bin 0 -> 425 bytes packages/core/images/window-title.gif | Bin 0 -> 275 bytes packages/core/images/window.gif | Bin 0 -> 75 bytes packages/core/src/index.ts | 2 + .../src/util/datatypes/style/mxEdgeStyle.js | 3 +- .../src/util/datatypes/style/mxStylesheet.js | 3 +- packages/core/webpack.config.js | 16 ++ packages/html/package.json | 2 +- packages/html/public/images/grid.gif | Bin 0 -> 58 bytes packages/html/stories/Anchors.stories.js | 131 +++++++++ .../html/stories/EdgeTolerance.stories.js | 120 ++++++++ packages/html/stories/ExtendCanvas.stories.js | 261 ++++++++++++++++++ packages/html/stories/Grid.stories.js | 16 +- packages/html/stories/HelloWorld.stories.js | 32 ++- webpack.config.js | 6 +- 32 files changed, 808 insertions(+), 34 deletions(-) create mode 100644 packages/core/css/common.css create mode 100644 packages/core/images/button.gif create mode 100644 packages/core/images/close.gif create mode 100644 packages/core/images/collapsed.gif create mode 100644 packages/core/images/error.gif create mode 100644 packages/core/images/expanded.gif create mode 100644 packages/core/images/maximize.gif create mode 100644 packages/core/images/minimize.gif create mode 100644 packages/core/images/normalize.gif create mode 100644 packages/core/images/point.gif create mode 100644 packages/core/images/resize.gif create mode 100644 packages/core/images/separator.gif create mode 100644 packages/core/images/submenu.gif create mode 100644 packages/core/images/transparent.gif create mode 100644 packages/core/images/warning.gif create mode 100644 packages/core/images/warning.png create mode 100644 packages/core/images/window-title.gif create mode 100644 packages/core/images/window.gif create mode 100644 packages/html/public/images/grid.gif create mode 100644 packages/html/stories/Anchors.stories.js create mode 100644 packages/html/stories/EdgeTolerance.stories.js create mode 100644 packages/html/stories/ExtendCanvas.stories.js diff --git a/package-lock.json b/package-lock.json index 7826818ac..8ec81d432 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4245,6 +4245,38 @@ "escape-string-regexp": "^1.0.5" } }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -5368,12 +5400,6 @@ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true }, - "klona": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", - "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", - "dev": true - }, "lerna": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/lerna/-/lerna-4.0.0.tgz", @@ -7270,16 +7296,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sass-loader": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-11.0.1.tgz", - "integrity": "sha512-Vp1LcP4slTsTNLEiDkTcm8zGN/XYYrZz2BZybQbliWA8eXveqA/AxsEjllQTpJbg2MzCsx/qNO48sHdZtOaxTw==", - "dev": true, - "requires": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" - } - }, "schema-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", @@ -8044,6 +8060,39 @@ "punycode": "^2.1.0" } }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index eb2e6f74a..482c8e645 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,9 @@ "lerna": "^4.0.0", "@lerna/filter-options": "4.0.0", "prettier": "^2.2.1", - "sass-loader": "^11.0.1", "style-loader": "^2.0.0", + "url-loader": "^4.1.1", + "file-loader": "^6.2.0", "webpack": "^5.32.0", "webpack-cli": "^4.6.0", "webpack-merge": "^5.7.3", diff --git a/packages/core/css/common.css b/packages/core/css/common.css new file mode 100644 index 000000000..21f389211 --- /dev/null +++ b/packages/core/css/common.css @@ -0,0 +1,166 @@ +div.mxRubberband { + position: absolute; + overflow: hidden; + border-style: solid; + border-width: 1px; + border-color: #0000FF; + background: #0077FF; +} +.mxCellEditor { + background: url(data:image/gif;base64,R0lGODlhMAAwAIAAAP///wAAACH5BAEAAAAALAAAAAAwADAAAAIxhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8egpAAA7); + _background: url('../images/transparent.gif'); + border-color: transparent; + border-style: solid; + display: inline-block; + position: absolute; + overflow: visible; + word-wrap: normal; + border-width: 0; + min-width: 1px; + resize: none; + padding: 0px; + margin: 0px; +} +.mxPlainTextEditor * { + padding: 0px; + margin: 0px; +} +div.mxWindow { + -webkit-box-shadow: 3px 3px 12px #C0C0C0; + -moz-box-shadow: 3px 3px 12px #C0C0C0; + box-shadow: 3px 3px 12px #C0C0C0; + background: url(data:image/gif;base64,R0lGODlhGgAUAIAAAOzs7PDw8CH5BAAAAAAALAAAAAAaABQAAAIijI+py70Ao5y02lud3lzhD4ZUR5aPiKajyZbqq7YyB9dhAQA7); + _background: url('../images/window.gif'); + border:1px solid #c3c3c3; + position: absolute; + overflow: hidden; + z-index: 1; +} +table.mxWindow { + border-collapse: collapse; + table-layout: fixed; + font-family: Arial; + font-size: 8pt; +} +td.mxWindowTitle { + background: url(data:image/gif;base64,R0lGODlhFwAXAMQAANfX18rKyuHh4c7OzsDAwMHBwc/Pz+Li4uTk5NHR0dvb2+jo6O/v79/f3/n5+dnZ2dbW1uPj44yMjNPT0+Dg4N3d3ebm5szMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAXABcAAAWQICESxWiW5Ck6bOu+MMvMdG3f86LvfO/rlqBwSCwaj8ikUohoOp/QaDNCrVqvWKpgezhsv+AwmEIum89ocmPNbrvf64p8Tq/b5Yq8fs/v5x+AgYKDhIAAh4iJiouHEI6PkJGSjhOVlpeYmZUJnJ2en6CcBqMDpaanqKgXq6ytrq+rAbKztLW2shK5uru8vbkhADs=) repeat-x; + _background: url('../images/window-title.gif') repeat-x; + text-overflow: ellipsis; + white-space: nowrap; + text-align: center; + font-weight: bold; + overflow: hidden; + height: 13px; + padding: 2px; + padding-top: 4px; + padding-bottom: 6px; + color: black; +} +td.mxWindowPane { + vertical-align: top; + padding: 0px; +} +div.mxWindowPane { + overflow: hidden; + position: relative; +} +td.mxWindowPane td { + font-family: Arial; + font-size: 8pt; +} +td.mxWindowPane input, td.mxWindowPane select, td.mxWindowPane textarea, td.mxWindowPane radio { + border-color: #8C8C8C; + border-style: solid; + border-width: 1px; + font-family: Arial; + font-size: 8pt; + padding: 1px; +} +td.mxWindowPane button { + background: url(data:image/gif;base64,R0lGODlhCgATALMAAP7+/t7e3vj4+Ojo6OXl5e/v7/n5+fb29vPz8/39/e3t7fHx8e7u7v///wAAAAAAACH5BAAAAAAALAAAAAAKABMAAAQ2MMlJhb0Y6c2X/2AhjiRjnqiirizqMkEsz0Rt30Ou7y8K/ouDcEg0GI9IgHLJbDif0Kh06owAADs=) repeat-x; + _background: url('../images/button.gif') repeat-x; + font-family: Arial; + font-size: 8pt; + padding: 2px; + float: left; +} +img.mxToolbarItem { + margin-right: 6px; + margin-bottom: 6px; + border-width: 1px; +} +select.mxToolbarCombo { + vertical-align: top; + border-style: inset; + border-width: 2px; +} +div.mxToolbarComboContainer { + padding: 2px; +} +img.mxToolbarMode { + margin: 2px; + margin-right: 4px; + margin-bottom: 4px; + border-width: 0px; +} +img.mxToolbarModeSelected { + margin: 0px; + margin-right: 2px; + margin-bottom: 2px; + border-width: 2px; + border-style: inset; +} +div.mxTooltip { + -webkit-box-shadow: 3px 3px 12px #C0C0C0; + -moz-box-shadow: 3px 3px 12px #C0C0C0; + box-shadow: 3px 3px 12px #C0C0C0; + background: #FFFFCC; + border-style: solid; + border-width: 1px; + border-color: black; + font-family: Arial; + font-size: 8pt; + position: absolute; + cursor: default; + padding: 4px; + color: black; +} +div.mxPopupMenu { + -webkit-box-shadow: 3px 3px 12px #C0C0C0; + -moz-box-shadow: 3px 3px 12px #C0C0C0; + box-shadow: 3px 3px 12px #C0C0C0; + background: url(data:image/gif;base64,R0lGODlhGgAUAIAAAOzs7PDw8CH5BAAAAAAALAAAAAAaABQAAAIijI+py70Ao5y02lud3lzhD4ZUR5aPiKajyZbqq7YyB9dhAQA7); + _background: url('../images/window.gif'); + position: absolute; + border-style: solid; + border-width: 1px; + border-color: black; +} +table.mxPopupMenu { + border-collapse: collapse; + margin-top: 1px; + margin-bottom: 1px; +} +tr.mxPopupMenuItem { + color: black; + cursor: pointer; +} +tr.mxPopupMenuItemHover { + background-color: #000066; + color: #FFFFFF; + cursor: pointer; +} +td.mxPopupMenuItem { + padding: 2px 30px 2px 10px; + white-space: nowrap; + font-family: Arial; + font-size: 8pt; +} +td.mxPopupMenuIcon { + background-color: #D0D0D0; + padding: 2px 4px 2px 4px; +} +.mxDisabled { + opacity: 0.2 !important; + cursor:default !important; +} diff --git a/packages/core/images/button.gif b/packages/core/images/button.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad55cab610a0422be13288ace4cf717afaf613b3 GIT binary patch literal 137 zcmZ?wbhEHbR|Gs_u z_T$Ho@7}%p|NlP&7%2W^0n<7l5@ZGgitAS1881_0U#MvDLd literal 0 HcmV?d00001 diff --git a/packages/core/images/close.gif b/packages/core/images/close.gif new file mode 100644 index 0000000000000000000000000000000000000000..1069e94bb6b8555de51a4a47b835d9d151277f97 GIT binary patch literal 70 zcmZ?wbhEHbi;Ln<76uT|0TCb>1}52_e)iM3A8yPJyt+jx#L{D5 UsmJ!p)D;WU9;@U9FfdpH0IG}?*Z=?k literal 0 HcmV?d00001 diff --git a/packages/core/images/collapsed.gif b/packages/core/images/collapsed.gif new file mode 100644 index 0000000000000000000000000000000000000000..0276444a611969e0437c83d0149e1481f89c77e8 GIT binary patch literal 877 zcmZ?wbhEHbi zGH1?|IZKxwySMh(wYA6YZQZ(e>)vBq_ntd;?A)<)_l{k=ckbM|YxnM5yZ8Ja2t2>{ z{QdLi??K@E|M&m@e+Pp9qhK@y24e{5fN}sRFEDTfG01Wl1T0`+X5yCPU^p1i;w-?% z)9^!q$)ST^UO?l31=E2J0U0iV6&wmcJrX0N*f2C$8O)^6RqcJHyZ$F8kCc5mz6V|$OCI|c;j&K)~d(ZCy z!Sm<$-hT%Y&w=Fo|Ifewe-8rR-+%x9{{Md<@f`^M0|A%-F-E~?2n;|7=zwwnC@(N@ z1T)C8XgDl5*uco5q#}@b$fc`YjY~mbA`?rOsHTko%fzIkoFd95S{{rGQcm)+N=%SA p_{q7Qo0To+!GeWM?OX=p2@M8`hnhJBxLhWV4q+~q qfC~=}wed3>_*4Wua_$n=589F;sC>LrTCyldLuj#62P-oZgEauQf)%F# literal 0 HcmV?d00001 diff --git a/packages/core/images/minimize.gif b/packages/core/images/minimize.gif new file mode 100644 index 0000000000000000000000000000000000000000..1e95e7cae4027b7a102220aed8629fa2cf0c7bc8 GIT binary patch literal 64 zcmZ?wbhEHb1}5>Ae(}?}yobAUf;iu8nsR)) NM#79r0ZB0iYXA(c5v~9L literal 0 HcmV?d00001 diff --git a/packages/core/images/normalize.gif b/packages/core/images/normalize.gif new file mode 100644 index 0000000000000000000000000000000000000000..34a8d302e7953ccd6e5af9a1f38866666c38ef43 GIT binary patch literal 845 zcmZ?wbhEHbWV4q+~r s2m^+OR(5H-5{bZvM><*L<8pRvSbVgDPcw|A^PP!E>{@(Bh{^STKLRWtPIuwJ9HO^ literal 0 HcmV?d00001 diff --git a/packages/core/images/separator.gif b/packages/core/images/separator.gif new file mode 100644 index 0000000000000000000000000000000000000000..5c1b89566807692c4e28c65b4ee33b4f42f4c9ba GIT binary patch literal 146 zcmZ?wbhEHbWMmLzIKseCRaxKC*ioEQQeIY5ThmgIT~twCTUXsum{pXQT~b}ul$Tjh zQCe41*)Vg)yvmBY`kGb-Qh?%57O-+15DBuAft5euf&=?PhJHf@r;RE-!b}X-00+?_ AJ^%m! literal 0 HcmV?d00001 diff --git a/packages/core/images/submenu.gif b/packages/core/images/submenu.gif new file mode 100644 index 0000000000000000000000000000000000000000..ffe76176db93a40bbfcb96e60789886f68de0e49 GIT binary patch literal 56 zcmZ?wbhEHb;jF-siv0egDVL!_|Id(Z?5>3=Gx)k9{Vl literal 0 HcmV?d00001 diff --git a/packages/core/images/warning.gif b/packages/core/images/warning.gif new file mode 100644 index 0000000000000000000000000000000000000000..705235f95c6a58100385aa6b689d40dcf6803fe4 GIT binary patch literal 276 zcmZ?wbhEHb6krfwI3maZ1RNY3K|z+q#g^684As?|OP2~PU8=cuZP2-M4A-umyLXS_ z-aUcu-zC0(SN#56^Z$R47UF^8e{Mh5kYH!W09PYD17=2`PQ{-roJI_S3_2iFK+a%b z4NFkzOUdlwESkk}g-3g*!v(=^-M0rmUXo~Q%f0Hw!qjYeRy3=G!B)-7ShX(a P^}Yg~^Ch|ciVW5Oz=%=n literal 0 HcmV?d00001 diff --git a/packages/core/images/warning.png b/packages/core/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..2f7878964ce8fcad001eaf06e3a60c751b781437 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIMT6?-UhE&{2`t$$4J+mrhyQQQZvOZ9GPi((1usJ;i`U=(|6(827jAr7AH&ALBH+jT?k=-;RE&T@EHsr`XJ3l_ZRadVU3uuDXt!61fV zv#dyijEqbIPf~I*tB0ZkL*fpHz(U!uZVQWd%&`X>75M}lH1r(4S#RP_VC;IwH9^6F zVdH~MvBAMj2Tywoo|!gf55G!$LoB0-z)?m9MwW8MsuPD7@wWsfy9fhSGk{co-o5l` zX&b-%g~N}m1hNnP1S&IQo&8oJCUz|+FEitsbqs|JOdXu@Cmu5iggeY(6L9ePA+l{t zO!|+1f7vfI@mpL4dQ|y@WKT~IkN0%0Kl{txGEdCAkdl$Rm+u<4KmvpO^52Wr-Yf=% OHG`+CpUXO@geCy=#hxkv literal 0 HcmV?d00001 diff --git a/packages/core/images/window-title.gif b/packages/core/images/window-title.gif new file mode 100644 index 0000000000000000000000000000000000000000..231def8bb5a44af3708c65e26d9d4196c00e8c94 GIT binary patch literal 275 zcmZ?wbhEHb6lV};IKsei{rdG&r%pY5`0(7ha|aF_IC${j`Sa%=J$m%y$&-s0FW$a= z`^AeF@87?_fB*i^pFeNjym{@~wa1Si_w@8!zI^$?g9mr--hKA$*_ktE7;pf^pDbV* z9S{k!lYw=Df}+sTjA>6at#V%PGdO*wB=`R3Mel3gzn-?Bz(Yr>|HP7@jtr~$7cz{U z)<&(5Sd~z1k+c7S!3-z8+2=EglF#PtzW=(b#&7-Yr(JvM&cA;y-_Y39+|t0%-qG3B z-7e7AKVjmeKH;g;rq7r;m2=MAdGi;{VOz|+blLJ1E5ui?S-WoiYQ{~Qw`|?ENoeP; M-Fx=#RAjIQ0Glw5tpET3 literal 0 HcmV?d00001 diff --git a/packages/core/images/window.gif b/packages/core/images/window.gif new file mode 100644 index 0000000000000000000000000000000000000000..6631c4f5f20e1090fbbbfce38c873e26f6259c0c GIT binary patch literal 75 zcmZ?wbhEHblwuHJXkcJ?^XAQm4<8hNvM_*v4u}BBFfb|g^shX 0) { @@ -634,7 +635,7 @@ class mxEdgeStyle { } } - const pe = pts[lastInx]; + pe = pts[lastInx]; if (pe != null && hints[hints.length - 1] != null) { if (Math.abs(hints[hints.length - 1].x - pe.x) < tol) { diff --git a/packages/core/src/util/datatypes/style/mxStylesheet.js b/packages/core/src/util/datatypes/style/mxStylesheet.js index d48a05e00..0be984d0e 100644 --- a/packages/core/src/util/datatypes/style/mxStylesheet.js +++ b/packages/core/src/util/datatypes/style/mxStylesheet.js @@ -7,6 +7,7 @@ import mxConstants from '../../mxConstants'; import mxPerimeter from './mxPerimeter'; import mxUtils from '../../mxUtils'; +import { clone } from '../../mxCloneUtils'; /** * @class mxStylesheet @@ -190,7 +191,7 @@ class mxStylesheet { const pairs = name.split(';'); if (style != null && name.charAt(0) !== ';') { - style = mxUtils.clone(style); + style = clone(style); } else { style = {}; } diff --git a/packages/core/webpack.config.js b/packages/core/webpack.config.js index 9f45b6c05..3e9c2a737 100644 --- a/packages/core/webpack.config.js +++ b/packages/core/webpack.config.js @@ -17,6 +17,22 @@ module.exports = merge(base, { library: 'mxgraph', libraryTarget: 'umd' }, + module: { + rules: [ + { + test: /\.(sa|sc|c)ss$/, + use: ['style-loader', 'css-loader'] + }, + { + test: /\.(ico|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/, + loader: 'url-loader', + options: { + name: 'images/[hash].[ext]', + limit: 10000, + }, + } + ] + }, plugins: [ new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1, diff --git a/packages/html/package.json b/packages/html/package.json index 349478b08..ae65a09c5 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "dev": "start-storybook -p 8901" + "dev": "start-storybook -p 8901 -s ./public" }, "author": "", "license": "ISC", diff --git a/packages/html/public/images/grid.gif b/packages/html/public/images/grid.gif new file mode 100644 index 0000000000000000000000000000000000000000..a82a20d00649dfc21f08e0c8c463ba044d5d82b6 GIT binary patch literal 58 zcmZ?wbhEHb { + const { + mxGraph, + mxEvent, + mxRubberband, + mxConnectionHandler, + mxConnectionConstraint, + mxGeometry, + mxPolyline, + mxPoint, + mxCellState + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + class MyCustomConnectionHandler extends mxConnectionHandler { + // Enables connect preview for the default edge style + createEdgeState(me) { + const edge = graph.createEdge(null, null, null, null, null); + return new mxCellState( + this.graph.view, + edge, + this.graph.getCellStyle(edge) + ); + } + } + + class MyCustomGraph extends mxGraph { + getAllConnectionConstraints(terminal, source) { + // Overridden to define per-shape connection points + if (terminal != null && terminal.shape != null) { + if (terminal.shape.stencil != null) { + if (terminal.shape.stencil.constraints != null) { + return terminal.shape.stencil.constraints; + } + } else if (terminal.shape.constraints != null) { + return terminal.shape.constraints; + } + } + return null; + } + + createConnectionHandler() { + return new MyCustomConnectionHandler(this); + } + } + + class MyCustomGeometryClass extends mxGeometry { + // Defines the default constraints for the vertices + constraints = [ + new mxConnectionConstraint(new mxPoint(0.25, 0), true), + new mxConnectionConstraint(new mxPoint(0.5, 0), true), + new mxConnectionConstraint(new mxPoint(0.75, 0), true), + new mxConnectionConstraint(new mxPoint(0, 0.25), true), + new mxConnectionConstraint(new mxPoint(0, 0.5), true), + new mxConnectionConstraint(new mxPoint(0, 0.75), true), + new mxConnectionConstraint(new mxPoint(1, 0.25), true), + new mxConnectionConstraint(new mxPoint(1, 0.5), true), + new mxConnectionConstraint(new mxPoint(1, 0.75), true), + new mxConnectionConstraint(new mxPoint(0.25, 1), true), + new mxConnectionConstraint(new mxPoint(0.5, 1), true), + new mxConnectionConstraint(new mxPoint(0.75, 1), true), + ]; + } + + // Edges have no connection points + mxPolyline.prototype.constraints = null; + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.setConnectable(true); + + // Specifies the default edge style + graph.getStylesheet().getDefaultEdgeStyle().edgeStyle = + 'orthogonalEdgeStyle'; + + // Enables rubberband selection + if (args.rubberBand) + new mxRubberband(graph); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + // Adds cells to the model in a single step + graph.batchUpdate(() => { + const v1 = graph.insertVertex({ + parent, + value: 'Hello,', + position: [20, 20], + size: [80, 30], + geometryClass: MyCustomGeometryClass, + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [200, 150], + size: [80, 30], + geometryClass: MyCustomGeometryClass, + }); + const e1 = graph.insertEdge({ + parent, + value: '', + position: v1, + size: v2, + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/EdgeTolerance.stories.js b/packages/html/stories/EdgeTolerance.stories.js new file mode 100644 index 000000000..e14ad4bc2 --- /dev/null +++ b/packages/html/stories/EdgeTolerance.stories.js @@ -0,0 +1,120 @@ +import mxgraph from '@mxgraph/core'; + +export default { + title: 'Connections/EdgeTolerance', + argTypes: { + width: { + type: 'number', + defaultValue: 800 + }, + height: { + type: 'number', + defaultValue: 600 + } + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'hidden'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.background = 'url(/images/grid.gif)'; + container.style.cursor = 'default'; + + class MyCustomGraph extends mxGraph { + fireMouseEvent(evtName, me, sender) { + // Overrides the mouse event dispatching mechanism to update the + // cell which is associated with the event in case the native hit + // detection did not return anything. + + // Checks if native hit detection did not return anything + if (me.getState() == null) { + // Updates the graph coordinates in the event since we need + // them here. Storing them in the event means the overridden + // method doesn't have to do this again. + if (me.graphX == null || me.graphY == null) { + const pt = mxUtils.convertPoint(container, me.getX(), me.getY()); + + me.graphX = pt.x; + me.graphY = pt.y; + } + + const cell = this.getCellAt(me.graphX, me.graphY); + if (this.getModel().isEdge(cell)) { + me.state = this.view.getState(cell); + + if (me.state != null && me.state.shape != null) { + this.container.style.cursor = me.state.shape.node.style.cursor; + } + } + } + + if (me.state == null) { + this.container.style.cursor = 'default'; + } + + super.fireMouseEvent(evtName, me, sender); + } + + dblClick(evt, cell) { + // Overrides double click handling to use the tolerance + if (cell == null) { + const pt = mxUtils.convertPoint( + el, + mxEvent.getClientX(evt), + mxEvent.getClientY(evt) + ); + cell = this.getCellAt(pt.x, pt.y); + } + super.dblClick(evt, cell); + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.setTolerance(20); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + // Adds cells to the model in a single step + graph.batchUpdate(() => { + const v1 = graph.insertVertex({ + parent, + value: 'Hello,', + position: [120, 120], + size: [80, 30], + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [400, 250], + size: [80, 30], + }); + const e1 = graph.insertEdge({ + parent, + source: v1, + target: v2, + style: 'edgeStyle=orthogonalEdgeStyle;', + }); + const e2 = graph.insertEdge({ + parent, + source: v2, + target: v1, + style: 'edgeStyle=orthogonalEdgeStyle;', + }); + }); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/ExtendCanvas.stories.js b/packages/html/stories/ExtendCanvas.stories.js new file mode 100644 index 000000000..41d9cc3e0 --- /dev/null +++ b/packages/html/stories/ExtendCanvas.stories.js @@ -0,0 +1,261 @@ +import mxgraph from '@mxgraph/core'; + +import HelloWorld from './HelloWorld.stories'; + +export default { + title: 'Backgrounds/ExtendCanvas', + argTypes: { + ...HelloWorld.argTypes + } +}; + +const Template = ({ label, ...args }) => { + const { + mxGraph, + mxEvent, + mxRubberband, + mxRectangle, + mxGraphView, + mxPoint, + mxDomHelpers, + mxUtils + } = mxgraph; + + const container = document.createElement('div'); + container.style.position = 'relative'; + container.style.overflow = 'auto'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; + container.style.cursor = 'default'; + container.style.background = 'url(/images/grid.gif)'; + + if (!args.contextMenu) + mxEvent.disableContextMenu(container); + + /** + * Specifies the size of the size for "tiles" to be used for a graph with + * scrollbars but no visible background page. A good value is large + * enough to reduce the number of repaints that is caused for auto- + * translation, which depends on this value, and small enough to give + * a small empty buffer around the graph. Default is 400x400. + */ + const scrollTileSize = new mxRectangle(0, 0, 400, 400); + + class MyCustomGraph extends mxGraph { + /** + * Returns the padding for pages in page view with scrollbars. + */ + getPagePadding() { + return new mxPoint( + Math.max(0, Math.round(this.container.offsetWidth - 34)), + Math.max(0, Math.round(this.container.offsetHeight - 34)) + ); + } + + /** + * Returns the size of the page format scaled with the page size. + */ + getPageSize() { + return this.pageVisible + ? new mxRectangle( + 0, + 0, + this.pageFormat.width * this.pageScale, + this.pageFormat.height * this.pageScale + ) + : scrollTileSize; + } + + /** + * Returns a rectangle describing the position and count of the + * background pages, where x and y are the position of the top, + * left page and width and height are the vertical and horizontal + * page count. + */ + getPageLayout() { + const size = this.pageVisible ? this.getPageSize() : scrollTileSize; + const bounds = this.getGraphBounds(); + + if (bounds.width === 0 || bounds.height === 0) { + return new mxRectangle(0, 0, 1, 1); + } + + // Computes untransformed graph bounds + const x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x); + const y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y); + const w = Math.floor(bounds.width / this.view.scale); + const h = Math.floor(bounds.height / this.view.scale); + + const x0 = Math.floor(x / size.width); + const y0 = Math.floor(y / size.height); + const w0 = Math.ceil((x + w) / size.width) - x0; + const h0 = Math.ceil((y + h) / size.height) - y0; + + return new mxRectangle(x0, y0, w0, h0); + } + + getPreferredPageSize(bounds, width, height) { + const pages = this.getPageLayout(); + const size = this.getPageSize(); + + return new mxRectangle( + 0, + 0, + pages.width * size.width, + pages.height * size.height + ); + } + + sizeDidChange() { + if (this.container != null && mxUtils.hasScrollbars(this.container)) { + const pages = this.getPageLayout(); + const pad = this.getPagePadding(); + const size = this.getPageSize(); + + // Updates the minimum graph size + const minw = Math.ceil( + (2 * pad.x) / this.view.scale + pages.width * size.width + ); + const minh = Math.ceil( + (2 * pad.y) / this.view.scale + pages.height * size.height + ); + + const min = this.minimumGraphSize; + + // LATER: Fix flicker of scrollbar size in IE quirks mode + // after delayed call in window.resize event handler + if (min == null || min.width !== minw || min.height !== minh) { + this.minimumGraphSize = new mxRectangle(0, 0, minw, minh); + } + + // Updates auto-translate to include padding and graph size + const dx = pad.x / this.view.scale - pages.x * size.width; + const dy = pad.y / this.view.scale - pages.y * size.height; + + if ( + !this.autoTranslate && + (this.view.translate.x !== dx || this.view.translate.y !== dy) + ) { + this.autoTranslate = true; + this.view.x0 = pages.x; + this.view.y0 = pages.y; + + // NOTE: THIS INVOKES THIS METHOD AGAIN. UNFORTUNATELY THERE IS NO WAY AROUND THIS SINCE THE + // BOUNDS ARE KNOWN AFTER THE VALIDATION AND SETTING THE TRANSLATE TRIGGERS A REVALIDATION. + // SHOULD MOVE TRANSLATE/SCALE TO VIEW. + const tx = this.view.translate.x; + const ty = this.view.translate.y; + + this.view.setTranslate(dx, dy); + this.container.scrollLeft += (dx - tx) * this.view.scale; + this.container.scrollTop += (dy - ty) * this.view.scale; + + this.autoTranslate = false; + return; + } + super.sizeDidChange(); + } + } + } + + // Creates the graph inside the given container + const graph = new MyCustomGraph(container); + graph.panningHandler.ignoreCell = true; + graph.setPanning(true); + + // Fits the number of background pages to the graph + graph.view.getBackgroundPageBounds = function() { + const layout = this.graph.getPageLayout(); + const page = this.graph.getPageSize(); + + return new mxRectangle( + this.scale * (this.translate.x + layout.x * page.width), + this.scale * (this.translate.y + layout.y * page.height), + this.scale * layout.width * page.width, + this.scale * layout.height * page.height + ); + }; + + /** + * Guesses autoTranslate to avoid another repaint (see below). + * Works if only the scale of the graph changes or if pages + * are visible and the visible pages do not change. + */ + const graphViewValidate = graph.view.validate; + graph.view.validate = function() { + if ( + this.graph.container != null && + mxUtils.hasScrollbars(this.graph.container) + ) { + const pad = this.graph.getPagePadding(); + const size = this.graph.getPageSize(); + + // Updating scrollbars here causes flickering in quirks and is not needed + // if zoom method is always used to set the current scale on the graph. + const tx = this.translate.x; + const ty = this.translate.y; + this.translate.x = pad.x / this.scale - (this.x0 || 0) * size.width; + this.translate.y = pad.y / this.scale - (this.y0 || 0) * size.height; + } + + graphViewValidate.apply(this, arguments); + }; + + // Enables rubberband selection + if (args.rubberBand) + new mxRubberband(graph); + + // Gets the default parent for inserting new cells. This + // is normally the first child of the root (ie. layer 0). + const parent = graph.getDefaultParent(); + + // Adds cells to the model in a single step + graph.batchUpdate(() => { + const v1 = graph.insertVertex({ + parent, + value: 'Hello,', + position: [20, 20], + size: [80, 30], + }); + const v2 = graph.insertVertex({ + parent, + value: 'World!', + position: [200, 150], + size: [80, 30], + }); + const e1 = graph.insertEdge({ + parent, + source: v1, + target: v2, + }); + }); + + // Sets initial scrollbar positions + window.setTimeout(() => { + const bounds = graph.getGraphBounds(); + const width = Math.max( + bounds.width, + scrollTileSize.width * graph.view.scale + ); + const height = Math.max( + bounds.height, + scrollTileSize.height * graph.view.scale + ); + graph.container.scrollTop = Math.floor( + Math.max( + 0, + bounds.y - Math.max(20, (graph.container.clientHeight - height) / 4) + ) + ); + graph.container.scrollLeft = Math.floor( + Math.max( + 0, + bounds.x - Math.max(0, (graph.container.clientWidth - width) / 2) + ) + ); + }, 0); + + return container; +} + +export const Default = Template.bind({}); \ No newline at end of file diff --git a/packages/html/stories/Grid.stories.js b/packages/html/stories/Grid.stories.js index 141c5e255..8efa60d75 100644 --- a/packages/html/stories/Grid.stories.js +++ b/packages/html/stories/Grid.stories.js @@ -1,7 +1,12 @@ import mxgraph from '@mxgraph/core'; +import HelloWorld from './HelloWorld.stories'; + export default { - title: 'Backgrounds/Grid' + title: 'Backgrounds/Grid', + argTypes: { + ...HelloWorld.argTypes + } }; const Template = ({ label, ...args }) => { @@ -21,11 +26,13 @@ const Template = ({ label, ...args }) => { const container = document.createElement('div'); container.style.position = 'relative'; container.style.overflow = 'hidden'; - container.style.height = '481px'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; container.style.cursor = 'default'; div.appendChild(container); - mxEvent.disableContextMenu(container); + if (!args.contextMenu) + mxEvent.disableContextMenu(container); // Creates the graph inside the given container var graph = new mxGraph(container); @@ -33,7 +40,8 @@ const Template = ({ label, ...args }) => { graph.setPanning(true); // Enables rubberband selection - new mxRubberband(graph); + if (args.rubberBand) + new mxRubberband(graph); let repaintGrid; diff --git a/packages/html/stories/HelloWorld.stories.js b/packages/html/stories/HelloWorld.stories.js index aa88b570d..2d4570c6c 100644 --- a/packages/html/stories/HelloWorld.stories.js +++ b/packages/html/stories/HelloWorld.stories.js @@ -1,7 +1,25 @@ import mxgraph from '@mxgraph/core'; export default { - title: 'Basic/HelloWorld' + title: 'Basic/HelloWorld', + argTypes: { + width: { + type: 'number', + defaultValue: 800 + }, + height: { + type: 'number', + defaultValue: 600 + }, + contextMenu: { + type: 'boolean', + defaultValue: false + }, + rubberBand: { + type: 'boolean', + defaultValue: true + } + } }; const Template = ({ label, ...args }) => { @@ -10,14 +28,17 @@ const Template = ({ label, ...args }) => { const container = document.createElement('div'); container.style.position = 'relative'; container.style.overflow = 'hidden'; - container.style.height = '241px'; + container.style.width = `${args.width}px`; + container.style.height = `${args.height}px`; container.style.cursor = 'default'; - mxEvent.disableContextMenu(container); + if (!args.contextMenu) + mxEvent.disableContextMenu(container); const graph = new mxGraph(container); - new mxRubberband(graph); + if (args.rubberBand) + new mxRubberband(graph); const parent = graph.getDefaultParent(); @@ -30,6 +51,7 @@ const Template = ({ label, ...args }) => { size: [80, 30], relative: false, }); + const vertex2 = graph.insertVertex({ parent, value: 'World!', @@ -37,9 +59,9 @@ const Template = ({ label, ...args }) => { size: [80, 30], relative: false, }); + const edge = graph.insertEdge({ parent, - // value: 'to the', source: vertex1, target: vertex2, }); diff --git a/webpack.config.js b/webpack.config.js index c5d1ed559..190009653 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,14 +11,10 @@ module.exports = { } }, exclude: /node_modules/ - }, - { - test: /\.(sa|sc|c)ss$/, - use: ['style-loader', 'css-loader', 'sass-loader'] } ] }, resolve: { - extensions: ['.ts', '.js', '.scss'] + extensions: ['.ts', '.js', '.css'] } } \ No newline at end of file