├── .npmignore ├── docs ├── demo.gif ├── demo.png ├── home-bg.jpg ├── fixes │ ├── planend.json │ ├── two-weaksafter.html │ ├── bug141.json │ ├── bug318.json │ ├── bug277.json │ ├── general.html │ ├── data-plan-color.json │ ├── lang.html │ └── data.json ├── main.css ├── main.js ├── project.xml ├── demobigdata.html ├── demo-plan-color.html ├── demo.html ├── index.js └── DotNet.md ├── .gitignore ├── index.ts ├── .github └── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md ├── e2e ├── tsconfig.e2e.json ├── app.po.ts └── app.e2e-spec.ts ├── test ├── index.ts └── index.html ├── tsconfig.json ├── .vscode └── launch.json ├── .travis.yml ├── protractor.conf.js ├── package.json ├── LICENSE ├── tslint.json ├── src ├── draw_dependencies.ts ├── json.ts ├── jsgantt.ts ├── utils │ ├── draw_utils.ts │ └── date_utils.ts ├── draw_columns.ts ├── options.ts ├── xml.ts └── events.ts ├── README.md └── CONTRIBUTING.md /.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | -------------------------------------------------------------------------------- /docs/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/HEAD/docs/demo.gif -------------------------------------------------------------------------------- /docs/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/HEAD/docs/demo.png -------------------------------------------------------------------------------- /docs/home-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/HEAD/docs/home-bg.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log 3 | package-lock.json 4 | /jsgantt.js 5 | .idea 6 | dist/src 7 | dist/e2e 8 | dist/test 9 | dist/index.* -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import 2 | * as jsGantt 3 | from './src/jsgantt'; 4 | 5 | declare var module: any; 6 | module.exports = jsGantt.JSGantt; 7 | 8 | export const JSGantt = jsGantt.JSGantt; 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Describe this issue template's purpose here. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as JSGantt from '../index'; 3 | import { expect } from 'chai'; 4 | import { browser, by, element } from 'protractor'; 5 | 6 | const dv = browser.driver; 7 | 8 | describe('Browser test', () => { 9 | it('JSGantt exists', () => { 10 | expect(JSGantt).to.exist; 11 | }); 12 | 13 | it('Driver exists', () => { 14 | expect(dv).to.exist; 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /docs/fixes/planend.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pid": 1, 4 | "pStart": "2019-03-07", 5 | "pEnd": "2020-07-31", 6 | "pPlanEnd": "2022-03-22", 7 | "pClass": "ggroupblack", 8 | "pName": "step 1" 9 | }, 10 | { 11 | 12 | "pid": 2, 13 | "pStart": "2022-03-23", 14 | "pEnd": "2023-12-14", 15 | "pPlanEnd": "2024-03-06", 16 | "pClass": "ggroupblack", 17 | "pName": "step 2" 18 | }, 19 | { 20 | "pid": 3, 21 | "pStart": "2024-03-07", 22 | "pEnd": "2025-08-26", 23 | "pPlanEnd": "2026-08-12", 24 | "pClass": "ggroupblack", 25 | "pName": "step 3" 26 | } 27 | ] -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ], 19 | "paths": { 20 | "jsgantt-improved": [ "dist/jsgantt-improved" ] 21 | } 22 | }, 23 | "exclude": [ 24 | ".ng_build" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class NgPackagedPage { 4 | navigateTo() { 5 | return browser.get('/docs/demo.html'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | 12 | getById(id) { 13 | return element(by.id(id)).getText(); 14 | } 15 | 16 | getValueById(id) { 17 | return element(by.id(id)).getAttribute('value'); 18 | } 19 | 20 | sendKeys(id, val) { 21 | element(by.id(id)).sendKeys(val); 22 | } 23 | 24 | submit() { 25 | element(by.id('submit')).click(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "ng e2e", 9 | "type": "node", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/node_modules/protractor/bin/protractor", 12 | "protocol": "inspector", 13 | "args": ["${workspaceFolder}/protractor.conf.js"] 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { NgPackagedPage } from './app.po'; 2 | 3 | import 'mocha'; 4 | import { element, by } from 'protractor'; 5 | 6 | describe('ng-packaged App', () => { 7 | let page: NgPackagedPage; 8 | 9 | beforeEach(() => { 10 | page = new NgPackagedPage(); 11 | return page.navigateTo(); 12 | }); 13 | 14 | afterEach(() => { 15 | page.navigateTo(); 16 | }); 17 | 18 | it('it should change language from pt to en', () => { 19 | element(by.css('.gtaskheading.gres')).getText() 20 | .then(t=>{ 21 | expect(t).toEqual('Resource'); 22 | element(by.cssContainingText('option', 'pt')).click(); 23 | return element(by.css('.gtaskheading.gres')).getText() 24 | }) 25 | .then(t=>{ 26 | expect(t).toEqual('Responsável'); 27 | }); 28 | }); 29 | }); 30 | 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "9" 4 | addons: 5 | chrome: stable 6 | services: 7 | - xvfb 8 | before_script: 9 | - "export DISPLAY=:99.0" 10 | # - "sh -e /etc/init.d/xvfb start" 11 | - sleep 3 # give xvfb some time to start 12 | - npm run dist 13 | - http-server & # start a Web server 14 | - sleep 3 # give Web server some time to bind to sockets, etc 15 | 16 | before_install: 17 | - npm install -g http-server browserify webdriver-manager 18 | - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16" 19 | - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost & 20 | 21 | install: 22 | - npm install 23 | - ./node_modules/protractor/bin/webdriver-manager update --versions.chrome 2.35 24 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:8080/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | browser.ignoreSynchronization = true; 24 | require('ts-node').register({ 25 | project: 'e2e/tsconfig.e2e.json' 26 | }); 27 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /docs/fixes/two-weaksafter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/fixes/bug141.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pID": 1, 4 | "pName": "Define Chart API", 5 | "pStart": "", 6 | "pEnd": "", 7 | "pPlanStart": "", 8 | "pPlanEnd": "", 9 | "pClass": "ggroupblack", 10 | "pLink": "", 11 | "pMile": 0, 12 | "pRes": "Mario", 13 | "pComp": 0, 14 | "pGroup": 1, 15 | "pParent": 0, 16 | "pOpen": 1, 17 | "pDepend": "", 18 | "pCaption": "", 19 | "pNotes": "", 20 | "category": "", 21 | "sector": "" 22 | }, 23 | { 24 | "pID": 11, 25 | "pName": "Chart Object", 26 | "pStart": "2018-06-20", 27 | "pEnd": "2018-07-20", 28 | "pClass": "gtaskpink", 29 | "pLink": "", 30 | "pMile": 0, 31 | "pRes": "Henrique", 32 | "pComp": 100, 33 | "pGroup": 0, 34 | "pParent": 1, 35 | "pOpen": 1, 36 | "pDepend": "", 37 | "pCaption": "", 38 | "pNotes": "", 39 | "category": "", 40 | "sector": "" 41 | }, 42 | { 43 | "pID": 12, 44 | "pName": "Task Objects", 45 | "pStart": "2018-08-10", 46 | "pEnd": "2018-09-10", 47 | "pClass": "gtaskblue", 48 | "pLink": "", 49 | "pMile": 0, 50 | "pRes": "Henrique", 51 | "pComp": 40, 52 | "pGroup": 0, 53 | "pParent": 1, 54 | "pOpen": 1, 55 | "pDepend": "", 56 | "pCaption": "", 57 | "pNotes": "" 58 | } 59 | ] -------------------------------------------------------------------------------- /docs/fixes/bug318.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pID": 1, 4 | "pName": "Define Chart API", 5 | "pStart": "2018-02-25", 6 | "pEnd": "2018-03-17", 7 | "pPlanStart": "2018-04-01", 8 | "pPlanEnd": "2018-04-15 12:00", 9 | "pClass": "ggroupblack", 10 | "pLink": "", 11 | "pMile": 0, 12 | "pRes": "Mario", 13 | "pComp": 0, 14 | "pGroup": 1, 15 | "pParent": 0, 16 | "pOpen": 1, 17 | "pDepend": "", 18 | "pCaption": "", 19 | "pNotes": "", 20 | "category": "", 21 | "sector": "" 22 | }, 23 | { 24 | "pID": 11, 25 | "pName": "Chart Object", 26 | "pStart": "2018-06-20", 27 | "pEnd": "2018-07-20", 28 | "pClass": "gtaskpink", 29 | "pLink": "", 30 | "pMile": 0, 31 | "pRes": "Henrique", 32 | "pComp": 100, 33 | "pGroup": 0, 34 | "pParent": 1, 35 | "pOpen": 1, 36 | "pDepend": "", 37 | "pCaption": "", 38 | "pNotes": "", 39 | "category": "", 40 | "sector": "" 41 | }, 42 | { 43 | "pID": 12, 44 | "pName": "Task Objects", 45 | "pStart": "2018-08-10", 46 | "pEnd": "2018-09-10", 47 | "pClass": "gtaskblue", 48 | "pLink": "", 49 | "pMile": 0, 50 | "pRes": "Henrique", 51 | "pComp": 40, 52 | "pGroup": 0, 53 | "pParent": 1, 54 | "pOpen": 1, 55 | "pDepend": "", 56 | "pCaption": "", 57 | "pNotes": "" 58 | } 59 | ] -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsgantt-improved", 3 | "version": "2.8.10", 4 | "description": "jsgantt-improved", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "start": "http-server", 8 | "build": "tsc", 9 | "watch:build": "onchange 'src/**' '*.*' -- npm run build", 10 | "watch": "onchange 'src/**' '*.ts' -- npm run dist", 11 | "watch:test": "onchange 'src/**/*.ts' '*.ts' 'e2e/**/*.ts' -- npm run test", 12 | "test": "npm start & node node_modules/.bin/protractor protractor.conf.js", 13 | "test-unit": "mocha -r ts-node/register test/**.ts", 14 | "webdriver": "./node_modules/protractor/bin/webdriver-manager update", 15 | "browserify": "browserify dist/index.js --standalone JSGantt > dist/jsgantt.js", 16 | "dist": "npm run build && npm run browserify && cp src/jsgantt.css dist/ && echo 'DIST finished'", 17 | "publishnpm": "npm run dist && npm publish", 18 | "demo-full": "npm run dist && npm run start", 19 | "e2e-prepare": "npm i -g webdriver-manager && webdriver-manager update && ./node_modules/protractor/node_modules/webdriver-manager/bin/webdriver-manager update" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/jsGanttImproved/jsgantt-improved" 24 | }, 25 | "author": "Mario Mol , Eduardo Rodrigues, Ricardo Cardoso", 26 | "license": "ISC", 27 | "bugs": { 28 | "url": "https://github.com/jsGanttImproved/jsgantt-improved/issues" 29 | }, 30 | "homepage": "https://jsganttimproved.github.io/jsgantt-improved/docs/", 31 | "dependencies": { 32 | "@types/node": "^12.0.10", 33 | "webdriver-manager": "^13.0.0" 34 | }, 35 | "devDependencies": { 36 | "@types/chai": "^4.1.5", 37 | "@types/jasmine": "^3.3.0", 38 | "chai": "^4.1.2", 39 | "http-server": "^0.11.1", 40 | "jasmine": "^3.3.0", 41 | "jasmine-core": "^3.3.0", 42 | "jasmine-spec-reporter": "^4.2.1", 43 | "mocha": "^5.2.0", 44 | "protractor": "^5.4.1", 45 | "selenium-webdriver": "^4.0.0-alpha.1", 46 | "ts-node": "^7.0.1", 47 | "typescript": "^3.0.3" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /docs/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | position: relative; 3 | } 4 | 5 | .product-name { 6 | font-family: Satisfy; 7 | } 8 | 9 | #my-navbar-nav { 10 | font-size: 16px; 11 | } 12 | 13 | #my-nav-brand { 14 | font-size: 24px; 15 | margin: 2px 40px 0 10px; 16 | color: #ffffff; 17 | } 18 | 19 | #home { 20 | background: #323232 url(home-bg.jpg) center 0 no-repeat; 21 | background-attachment: fixed; 22 | background-size: cover; 23 | min-height: 660px; 24 | color: #ffffff; 25 | } 26 | #home-title { 27 | font-size: 70px; 28 | margin-top: 180px; 29 | } 30 | #home-subtitle { 31 | font-size: 36px; 32 | margin-top: 40px; 33 | margin-bottom: 50px; 34 | } 35 | #learn-more { 36 | padding: 0; 37 | width: 50px; 38 | height: 50px; 39 | border-radius: 50%; 40 | font-size: 38px; 41 | margin-top: 60px; 42 | } 43 | @media screen and (max-width: 991px) { 44 | #learn-more { 45 | display: none; 46 | } 47 | } 48 | 49 | .section { 50 | margin: 0 15vw; 51 | padding: 5px 0 0; 52 | } 53 | 54 | h1 { 55 | font-family: Kelly Slab; 56 | font-size: 56px; 57 | margin: 50px 0 20px; 58 | } 59 | 60 | h2 { 61 | font-family: Kelly Slab; 62 | margin: 20px 0 10px; 63 | } 64 | 65 | h3 { 66 | font-family: Kelly Slab; 67 | } 68 | #embedded-Gantt, #external-Gantt { 69 | } 70 | 71 | .code-block { 72 | background-color: #222222; 73 | } 74 | 75 | .contact-card { 76 | max-width: 200px; 77 | margin: auto; 78 | } 79 | 80 | .contact-link { 81 | font-size: 28px; 82 | } 83 | 84 | .footer { 85 | margin-top: 10px; 86 | padding-top: 10px; 87 | border-top: solid #bbbbbb 1px; 88 | } 89 | 90 | #slide-card { 91 | background: transparent; 92 | border: none; 93 | margin: 180px 50px 50px; 94 | } 95 | #slide-dots { 96 | background: transparent; 97 | border: none; 98 | } 99 | .dot { 100 | cursor:pointer; 101 | height: 13px; 102 | width: 13px; 103 | margin: 0 2px; 104 | background-color: #ffffff; 105 | opacity: 0.3; 106 | border-radius: 50%; 107 | display: inline-block; 108 | -webkit-transition: all .5s; /* Safari */ 109 | transition: all .5s; 110 | } 111 | .dot:hover { 112 | opacity: 1; 113 | } 114 | .dot.active { 115 | opacity: 1; 116 | } 117 | .slide { 118 | width: 100%; 119 | height: 150px; 120 | font-size: 20px; 121 | display: none; 122 | opacity: 0; 123 | } 124 | .slide-icon { 125 | font-size: 60px; 126 | } 127 | -------------------------------------------------------------------------------- /docs/main.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | 3 | // Scrollspy changes navbar active links 4 | $("body").scrollspy({target:"#my-navbar-nav", offset:50}); 5 | 6 | // Smooth scroll 7 | $("a").click(function(event) { 8 | if (this.hash !== "") { 9 | event.preventDefault(); 10 | var linkOffset = 0; 11 | if ($.inArray(this.hash,["#options","#xmlExport","#optionsLanguage","#setDayMajorDateDisplayFormat"]) != -1) { 12 | linkOffset = -25; 13 | } 14 | $("html, body").animate({ 15 | scrollTop: $(this.hash).offset().top - $(".navbar").height() + linkOffset 16 | }, 600); 17 | } 18 | }); 19 | 20 | // Demo buttons 21 | $("#embedded-Gantt").hide(0); 22 | $("#external-Gantt").hide(0); 23 | 24 | $(".btn-demo").click(function() { 25 | if ($(this).html().indexOf("Embedded Code") != -1) { 26 | if ($("#external-Gantt").is(":visible")) { 27 | $("#external-Gantt").animate({ 28 | height: "toggle", 29 | opacity: "toggle"}, 300, function () { 30 | $("#embedded-Gantt").animate({ 31 | height: "toggle", 32 | opacity: "toggle"}, 600 33 | ); 34 | } 35 | ); 36 | $(".btn-demo:nth-child(2)").removeClass("active"); 37 | } else { 38 | $("#embedded-Gantt").animate({ 39 | height: "toggle", 40 | opacity: "toggle"}, 600 41 | ); 42 | } 43 | } else { 44 | if ($("#embedded-Gantt").is(":visible")) { 45 | $("#embedded-Gantt").animate({ 46 | height: "toggle", 47 | opacity: "toggle"}, 300, function() { 48 | $("#external-Gantt").animate({ 49 | height: "toggle", 50 | opacity: "toggle"}, 600 51 | ); 52 | } 53 | ); 54 | $(".btn-demo:nth-child(1)").removeClass("active"); 55 | } else { 56 | $("#external-Gantt").animate({ 57 | height: "toggle", 58 | opacity: "toggle"}, 600 59 | ); 60 | } 61 | } 62 | }); 63 | 64 | // Slideshow 65 | var slideIndex = 0; 66 | carousel(); 67 | 68 | function carousel() { 69 | var i; 70 | var x = document.getElementsByClassName("slide"); 71 | var d = document.getElementsByClassName("dot"); 72 | for (i = 0; i < x.length; i++) { 73 | x[i].style.display = "none"; 74 | } 75 | slideIndex++; 76 | if (slideIndex > x.length) {slideIndex = 1} 77 | x[slideIndex-1].style.display = "inline-block"; 78 | $(".slide:nth-child(" + (slideIndex).toString() + ")").animate({ 79 | opacity: 1 80 | }, 500); 81 | $(".dot").removeClass("active"); 82 | $(".dot:nth-child(" + (slideIndex).toString() + ")").addClass("active"); 83 | setTimeout(carousel, 2000); // Change image every 2 seconds 84 | } 85 | }); 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | * Copyright (c) 2013-2018, Paul Geldart, Eduardo Rodrigues and Ricardo Cardoso. 2 | * 3 | * Redistribution and use in source and binary forms, with or without 4 | * modification, are permitted provided that the following conditions are met: 5 | * * Redistributions of source code must retain the above copyright 6 | * notice, this list of conditions and the following disclaimer. 7 | * * Redistributions in binary form must reproduce the above copyright 8 | * notice, this list of conditions and the following disclaimer in the 9 | * documentation and/or other materials provided with the distribution. 10 | * * Neither the name of Paul Geldart, Eduardo Rodrigues and Ricardo Cardoso nor the names of its contributors 11 | * may be used to endorse or promote products derived from this software 12 | * without specific prior written permission. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY PAUL GELDART, EDUARDO RODRIGUES AND RICARDO CARDOSO ''AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL PAUL GELDART, EDUARDO RODRIGUES AND RICARDO CARDOSO BE LIABLE FOR ANY DIRECT, 18 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | This project is based on jsGantt 1.2, the original project license follows: 26 | 27 | * Copyright (c) 2008, Shlomy Gantz/BlueBrick Inc. 28 | * 29 | * Redistribution and use in source and binary forms, with or without 30 | * modification, are permitted provided that the following conditions are met: 31 | * * Redistributions of source code must retain the above copyright 32 | * notice, this list of conditions and the following disclaimer. 33 | * * Redistributions in binary form must reproduce the above copyright 34 | * notice, this list of conditions and the following disclaimer in the 35 | * documentation and/or other materials provided with the distribution. 36 | * * Neither the name of Shlomy Gantz or BlueBrick Inc. nor the 37 | * names of its contributors may be used to endorse or promote products 38 | * derived from this software without specific prior written permission. 39 | * 40 | * THIS SOFTWARE IS PROVIDED BY SHLOMY GANTZ/BLUEBRICK INC. ''AS IS'' AND ANY 41 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 42 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 43 | * DISCLAIMED. IN NO EVENT SHALL SHLOMY GANTZ/BLUEBRICK INC. BE LIABLE FOR ANY 44 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 45 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 47 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 48 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 49 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "callable-types": true, 7 | "class-name": true, 8 | "comment-format": [ 9 | true, 10 | "check-space" 11 | ], 12 | "curly": true, 13 | "eofline": true, 14 | "forin": true, 15 | "import-blacklist": [ 16 | true, 17 | "rxjs" 18 | ], 19 | "import-spacing": true, 20 | "indent": [ 21 | true, 22 | "spaces" 23 | ], 24 | "interface-over-type-literal": true, 25 | "label-position": true, 26 | "max-line-length": [ 27 | true, 28 | 140 29 | ], 30 | "member-access": false, 31 | "member-ordering": [ 32 | true, 33 | "static-before-instance", 34 | "variables-before-functions" 35 | ], 36 | "no-arg": true, 37 | "no-bitwise": true, 38 | "no-console": [ 39 | true, 40 | "debug", 41 | "info", 42 | "time", 43 | "timeEnd", 44 | "trace" 45 | ], 46 | "no-construct": true, 47 | "no-debugger": true, 48 | "no-empty": false, 49 | "no-empty-interface": true, 50 | "no-eval": true, 51 | "no-inferrable-types": [ 52 | true, 53 | "ignore-params" 54 | ], 55 | "no-shadowed-variable": true, 56 | "no-string-literal": false, 57 | "no-string-throw": true, 58 | "no-switch-case-fall-through": true, 59 | "no-trailing-whitespace": true, 60 | "no-unused-expression": true, 61 | "no-use-before-declare": true, 62 | "no-var-keyword": true, 63 | "object-literal-sort-keys": false, 64 | "one-line": [ 65 | true, 66 | "check-open-brace", 67 | "check-catch", 68 | "check-else", 69 | "check-whitespace" 70 | ], 71 | "prefer-const": true, 72 | "quotemark": [ 73 | true, 74 | "single" 75 | ], 76 | "radix": true, 77 | "semicolon": [ 78 | "always" 79 | ], 80 | "triple-equals": [ 81 | true, 82 | "allow-null-check" 83 | ], 84 | "typedef-whitespace": [ 85 | true, 86 | { 87 | "call-signature": "nospace", 88 | "index-signature": "nospace", 89 | "parameter": "nospace", 90 | "property-declaration": "nospace", 91 | "variable-declaration": "nospace" 92 | } 93 | ], 94 | "typeof-compare": true, 95 | "unified-signatures": true, 96 | "variable-name": false, 97 | "whitespace": [ 98 | true, 99 | "check-branch", 100 | "check-decl", 101 | "check-operator", 102 | "check-separator", 103 | "check-type" 104 | ], 105 | "directive-selector": [ 106 | true, 107 | "attribute", 108 | "app", 109 | "camelCase" 110 | ], 111 | "component-selector": [ 112 | true, 113 | "element", 114 | "app", 115 | "kebab-case" 116 | ], 117 | "use-input-property-decorator": true, 118 | "use-output-property-decorator": true, 119 | "use-host-property-decorator": true, 120 | "no-input-rename": true, 121 | "no-output-rename": true, 122 | "use-life-cycle-interface": true, 123 | "use-pipe-transform-interface": true, 124 | "component-class-suffix": true, 125 | "directive-class-suffix": true, 126 | "no-access-missing-member": true, 127 | "templates-use-public": true, 128 | "invoke-injectable": true 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /docs/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 5 | WCF Changes 6 | 7 | 8 | ggroupblack 9 | 10 | 0 11 | 12 | 0 13 | 1 14 | 0 15 | 1 16 | 17 | 18 | 19 | 20 20 | Move to WCF from remoting 21 | 2017-05-11 09:00 22 | 2017-05-15 23 | gtaskblue 24 | 25 | 0 26 | Paul 27 | 10 28 | 0 29 | 10 30 | 1 31 | 32 | Paul 33 | This text is only available in tool tips 34 | 35 | 36 | 30 37 | add Auditing 38 | 2017-05-18 10:30 39 | 2017-05-20 12:00 40 | gtaskblue 41 | 42 | 0 43 | Eduardo 44 | 50 45 | 0 46 | 10 47 | 1 48 | 20 49 | Eduardo 50 | 51 | 52 | 40 53 | Yet another task 54 | 2017-05-24 55 | 2017-05-25 56 | gtaskblue 57 | 58 | 0 59 | Ricardo 60 | 30 61 | 0 62 | 0 63 | 1 64 | 20,30 65 | Ricardo 66 | 67 | 68 | 50 69 | Another Group 70 | 71 | 72 | ggroupblack 73 | 74 | 0 75 | 76 | 0 77 | 1 78 | 0 79 | 1 80 | 81 | 82 | 83 | 60 84 | Move to GitHub 85 | 2017-05-14 09:00 86 | 2017-05-16 87 | gtaskblue 88 | 89 | 0 90 | Ricardo 91 | 10 92 | 0 93 | 50 94 | 1 95 | 96 | Ricardo 97 | This text is only available in tool tips 98 | 99 | 100 | 70 101 | Updating files 102 | 2017-05-18 10:30 103 | 2017-05-21 12:00 104 | gtaskred 105 | 106 | 0 107 | Paul 108 | 50 109 | 0 110 | 50 111 | 1 112 | 60 113 | Paul 114 | 115 | 116 | 80 117 | Yet another task 118 | 2017-05-23 119 | 2017-05-25 120 | gtaskyellow 121 | 122 | 0 123 | Eduardo 124 | 30 125 | 0 126 | 50 127 | 1 128 | 60,70 129 | Eduardo 130 | gtaskyellow 131 | 132 | 133 | -------------------------------------------------------------------------------- /docs/fixes/bug277.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pID": 206, 4 | "pName": "Graphs Test", 5 | "pStart": "2019-01-01", 6 | "pEnd": "2019-12-31", 7 | "pClass": "gnogantt", 8 | "pLink": "", 9 | "pMile": 0, 10 | "pComp": 0, 11 | "pGroup": 1, 12 | "pParent": 0, 13 | "pOpen": 1, 14 | "pCaption": "Proj", 15 | "predecessor": "" 16 | }, 17 | { 18 | "pID": 275, 19 | "pName": "Pre-Project", 20 | "pStart": "2019-01-01", 21 | "pEnd": "2020-01-01", 22 | "pClass": "gnogantt", 23 | "pLink": "", 24 | "pMile": 1, 25 | "pComp": 0, 26 | "pGroup": 1, 27 | "pParent": 206, 28 | "pOpen": 1, 29 | "pCaption": "Mile", 30 | "pNotes": "", 31 | "predecessor": "" 32 | }, 33 | { 34 | "pID": -2050515367, 35 | "pName": "Teste1", 36 | "pStart": "2019-01-01", 37 | "pEnd": "2019-01-11", 38 | "pPlanStart": "2019-01-01", 39 | "pPlanEnd": "2019-01-11", 40 | "pClass": "gtaskblue", 41 | "pLink": "", 42 | "pMile": 0, 43 | "pComp": 0, 44 | "pGroup": 2, 45 | "pParent": 275, 46 | "pOpen": 1, 47 | "pCaption": "Task", 48 | "pNotes": "", 49 | "predecessor": "", 50 | "appendedTaskId": 1208 51 | }, 52 | { 53 | "pID": 1208, 54 | "pName": "Teste1", 55 | "pStart": "2019-01-01", 56 | "pEnd": "2019-01-11", 57 | "pClass": "gtaskblue", 58 | "pLink": "", 59 | "pMile": 0, 60 | "pComp": 0, 61 | "pGroup": 0, 62 | "pParent": -2050515367, 63 | "pDepend": "", 64 | "pOpen": 1, 65 | "pCaption": "Task", 66 | "pNotes": "", 67 | "project": "206" 68 | }, 69 | { 70 | "pID": 12098745, 71 | "pName": "Teste2", 72 | "pStart": "2019-01-12", 73 | "pEnd": "2019-01-16", 74 | "pPlanStart": "2019-01-12", 75 | "pPlanEnd": "2019-01-16", 76 | "pClass": "gtaskblue", 77 | "pLink": "", 78 | "pMile": 0, 79 | "pComp": 0, 80 | "pGroup": 2, 81 | "pParent": 275, 82 | "pOpen": 1, 83 | "pCaption": "Task", 84 | "pNotes": "", 85 | "predecessor": "1208", 86 | "appendedTaskId": 1209 87 | }, 88 | { 89 | "pID": 8745, 90 | "pName": "Appointments Interval", 91 | "pStart": "2019-01-11", 92 | "pEnd": "2019-01-12", 93 | "pClass": "gappointment", 94 | "pLink": "", 95 | "pMile": 0, 96 | "pComp": 0, 97 | "pGroup": 0, 98 | "pParent": 12098745, 99 | "pDepend": "", 100 | "pOpen": 1, 101 | "pCaption": "Appointments Interval", 102 | "pNotes": "", 103 | "project": "206" 104 | }, 105 | { 106 | "pID": 1209, 107 | "pName": "Teste2", 108 | "pStart": "2019-01-12", 109 | "pEnd": "2019-01-16", 110 | "pClass": "gtaskblue", 111 | "pLink": "", 112 | "pMile": 0, 113 | "pComp": 0, 114 | "pGroup": 0, 115 | "pParent": 12098745, 116 | "pDepend": "1208", 117 | "pOpen": 1, 118 | "pCaption": "Task", 119 | "pNotes": "", 120 | "project": "206" 121 | }, 122 | { 123 | "pID": 1220317130, 124 | "pName": "Teste3", 125 | "pStart": "2019-01-17", 126 | "pEnd": "2019-01-17", 127 | "pPlanStart": "2019-01-17", 128 | "pPlanEnd": "2019-01-17", 129 | "pClass": "gtaskblue", 130 | "pLink": "", 131 | "pMile": 0, 132 | "pComp": 0, 133 | "pGroup": 2, 134 | "pParent": 275, 135 | "pOpen": 1, 136 | "pCaption": "Task", 137 | "pNotes": "", 138 | "predecessor": "1209", 139 | "appendedTaskId": 1210 140 | }, 141 | { 142 | "pID": 1210, 143 | "pName": "Teste3", 144 | "pStart": "2019-01-17", 145 | "pEnd": "2019-01-17", 146 | "pClass": "gtaskblue", 147 | "pLink": "", 148 | "pMile": 0, 149 | "pComp": 0, 150 | "pGroup": 0, 151 | "pParent": 1220317130, 152 | "pDepend": "1209", 153 | "pOpen": 1, 154 | "pCaption": "Task", 155 | "pNotes": "", 156 | "project": "206" 157 | } 158 | ] -------------------------------------------------------------------------------- /src/draw_dependencies.ts: -------------------------------------------------------------------------------- 1 | export const drawDependency = function (x1, y1, x2, y2, pType, pClass) { 2 | let vDir = 1; 3 | let vBend = false; 4 | let vShort = 4; 5 | let vRow = Math.floor(this.getRowHeight() / 2); 6 | 7 | if (y2 < y1) vRow *= -1; 8 | 9 | switch (pType) { 10 | case 'SF': 11 | vShort *= -1; 12 | if (x1 - 10 <= x2 && y1 != y2) vBend = true; 13 | vDir = -1; 14 | break; 15 | case 'SS': 16 | if (x1 < x2) vShort *= -1; 17 | else vShort = x2 - x1 - (2 * vShort); 18 | break; 19 | case 'FF': 20 | if (x1 <= x2) vShort = x2 - x1 + (2 * vShort); 21 | vDir = -1; 22 | break; 23 | default: 24 | if (x1 + 10 >= x2 && y1 != y2) vBend = true; 25 | break; 26 | } 27 | 28 | if (vBend) { 29 | this.sLine(x1, y1, x1 + vShort, y1, pClass); 30 | this.sLine(x1 + vShort, y1, x1 + vShort, y2 - vRow, pClass); 31 | this.sLine(x1 + vShort, y2 - vRow, x2 - (vShort * 2), y2 - vRow, pClass); 32 | this.sLine(x2 - (vShort * 2), y2 - vRow, x2 - (vShort * 2), y2, pClass); 33 | this.sLine(x2 - (vShort * 2), y2, x2 - (1 * vDir), y2, pClass); 34 | } 35 | else if (y1 != y2) { 36 | this.sLine(x1, y1, x1 + vShort, y1, pClass); 37 | this.sLine(x1 + vShort, y1, x1 + vShort, y2, pClass); 38 | this.sLine(x1 + vShort, y2, x2 - (1 * vDir), y2, pClass); 39 | } 40 | else this.sLine(x1, y1, x2 - (1 * vDir), y2, pClass); 41 | 42 | let vTmpDiv = this.sLine(x2, y2, x2 - 3 - ((vDir < 0) ? 1 : 0), y2 - 3 - ((vDir < 0) ? 1 : 0), pClass + "Arw"); 43 | vTmpDiv.style.width = '0px'; 44 | vTmpDiv.style.height = '0px'; 45 | }; 46 | 47 | export const DrawDependencies = function (vDebug = false) { 48 | if (this.getShowDeps() == 1) { 49 | 50 | this.CalcTaskXY(); //First recalculate the x,y 51 | this.clearDependencies(); 52 | 53 | let vList = this.getList(); 54 | for (let i = 0; i < vList.length; i++) { 55 | let vDepend = vList[i].getDepend(); 56 | let vDependType = vList[i].getDepType(); 57 | let n = vDepend.length; 58 | 59 | if (n > 0 && vList[i].getVisible() == 1) { 60 | for (let k = 0; k < n; k++) { 61 | let vTask = this.getArrayLocationByID(vDepend[k]); 62 | if (vTask >= 0 && vList[vTask].getGroup() != 2) { 63 | if (vList[vTask].getVisible() == 1) { 64 | if (vDebug) { 65 | console.info(`init drawDependency `, vList[vTask].getID(), new Date()); 66 | } 67 | var cssClass = 'gDepId' + vList[vTask].getID() + 68 | ' ' + 'gDepNextId' + vList[i].getID(); 69 | 70 | var dependedData = vList[vTask].getDataObject(); 71 | var nextDependedData = vList[i].getDataObject(); 72 | if (dependedData && dependedData.pID && nextDependedData && nextDependedData.pID) { 73 | cssClass += ' gDepDataId' + dependedData.pID + ' ' + 'gDepNextDataId' + nextDependedData.pID; 74 | } 75 | 76 | if (vDependType[k] == 'SS') this.drawDependency(vList[vTask].getStartX() - 1, vList[vTask].getStartY(), vList[i].getStartX() - 1, vList[i].getStartY(), 'SS', cssClass + ' gDepSS'); 77 | else if (vDependType[k] == 'FF') this.drawDependency(vList[vTask].getEndX(), vList[vTask].getEndY(), vList[i].getEndX(), vList[i].getEndY(), 'FF', cssClass + ' gDepFF'); 78 | else if (vDependType[k] == 'SF') this.drawDependency(vList[vTask].getStartX() - 1, vList[vTask].getStartY(), vList[i].getEndX(), vList[i].getEndY(), 'SF', cssClass + ' gDepSF'); 79 | else if (vDependType[k] == 'FS') this.drawDependency(vList[vTask].getEndX(), vList[vTask].getEndY(), vList[i].getStartX() - 1, vList[i].getStartY(), 'FS', cssClass + ' gDepFS'); 80 | } 81 | } 82 | } 83 | } 84 | } 85 | } 86 | // draw the current date line 87 | if (this.vTodayPx >= 0) { 88 | this.sLine(this.vTodayPx, 0, this.vTodayPx, this.getChartTable().offsetHeight - 1, 'gCurDate'); 89 | } 90 | }; 91 | -------------------------------------------------------------------------------- /src/json.ts: -------------------------------------------------------------------------------- 1 | import { TaskItem } from "./task"; 2 | import { makeRequest } from "./utils/general_utils"; 3 | 4 | /** 5 | * 6 | * @param pFile 7 | * @param pGanttlet 8 | */ 9 | export const parseJSON = async function (pFile, pGanttVar, vDebug = false, redrawAfter = true) { 10 | const jsonObj = await makeRequest(pFile, true, true); 11 | let bd; 12 | if (vDebug) { 13 | bd = new Date(); 14 | console.info('before jsonparse', bd); 15 | } 16 | addJSONTask(pGanttVar, jsonObj); 17 | if (this.vDebug) { 18 | const ad = new Date(); 19 | console.info('after addJSONTask', ad, (ad.getTime() - bd.getTime())); 20 | } 21 | if(redrawAfter){ 22 | pGanttVar.Draw(); 23 | } 24 | return jsonObj; 25 | }; 26 | 27 | export const parseJSONString = function (pStr, pGanttVar) { 28 | addJSONTask(pGanttVar, JSON.parse(pStr)); 29 | }; 30 | 31 | export const addJSONTask = function (pGanttVar, pJsonObj) { 32 | for (let index = 0; index < pJsonObj.length; index++) { 33 | let id; 34 | let name; 35 | let start; 36 | let end; 37 | let planstart; 38 | let planend; 39 | let itemClass; 40 | let planClass; 41 | let link = ''; 42 | let milestone = 0; 43 | let resourceName = ''; 44 | let completion; 45 | let group = 0; 46 | let parent; 47 | let open; 48 | let dependsOn = ''; 49 | let caption = ''; 50 | let notes = ''; 51 | let cost; 52 | let duration = ''; 53 | let bartext = ''; 54 | const additionalObject = {}; 55 | 56 | for (let prop in pJsonObj[index]) { 57 | let property = prop; 58 | let value = pJsonObj[index][property]; 59 | switch (property.toLowerCase()) { 60 | case 'pid': 61 | case 'id': 62 | id = value; 63 | break; 64 | case 'pname': 65 | case 'name': 66 | name = value; 67 | break; 68 | case 'pstart': 69 | case 'start': 70 | start = value; 71 | break; 72 | case 'pend': 73 | case 'end': 74 | end = value; 75 | break; 76 | case 'pplanstart': 77 | case 'planstart': 78 | planstart = value; 79 | break; 80 | case 'pplanend': 81 | case 'planend': 82 | planend = value; 83 | break; 84 | case 'pclass': 85 | case 'class': 86 | itemClass = value; 87 | break; 88 | case 'pplanclass': 89 | case 'planclass': 90 | planClass = value; 91 | break; 92 | case 'plink': 93 | case 'link': 94 | link = value; 95 | break; 96 | case 'pmile': 97 | case 'mile': 98 | milestone = value; 99 | break; 100 | case 'pres': 101 | case 'res': 102 | resourceName = value; 103 | break; 104 | case 'pcomp': 105 | case 'comp': 106 | completion = value; 107 | break; 108 | case 'pgroup': 109 | case 'group': 110 | group = value; 111 | break; 112 | case 'pparent': 113 | case 'parent': 114 | parent = value; 115 | break; 116 | case 'popen': 117 | case 'open': 118 | open = value; 119 | break; 120 | case 'pdepend': 121 | case 'depend': 122 | dependsOn = value; 123 | break; 124 | case 'pcaption': 125 | case 'caption': 126 | caption = value; 127 | break; 128 | case 'pnotes': 129 | case 'notes': 130 | notes = value; 131 | break; 132 | case 'pcost': 133 | case 'cost': 134 | cost = value; 135 | break; 136 | case 'duration': 137 | case 'pduration': 138 | duration = value; 139 | break; 140 | case 'bartext': 141 | case 'pbartext': 142 | bartext = value; 143 | break; 144 | default: 145 | additionalObject[property.toLowerCase()] = value; 146 | } 147 | } 148 | 149 | //if (id != undefined && !isNaN(parseInt(id)) && isFinite(id) && name && start && end && itemClass && completion != undefined && !isNaN(parseFloat(completion)) && isFinite(completion) && !isNaN(parseInt(parent)) && isFinite(parent)) { 150 | pGanttVar.AddTaskItem(new TaskItem(id, name, start, end, itemClass, link, 151 | milestone, resourceName, completion, group, parent, open, dependsOn, 152 | caption, notes, pGanttVar, cost, planstart, planend, duration, bartext, 153 | additionalObject, planClass)); 154 | //} 155 | } 156 | }; 157 | -------------------------------------------------------------------------------- /src/jsgantt.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2018, Paul Geldart, Eduardo Rodrigues, Ricardo Cardoso and Mario Mol. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of AUTHORS nor the names of its contributors 12 | * may be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL AUTHORS BE LIABLE FOR ANY DIRECT, 19 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | This project is based on jsGantt 1.2, (which can be obtained from 27 | https://code.google.com/p/jsgantt/) and remains under the original BSD license. 28 | Copyright (c) 2009, Shlomy Gantz BlueBrick Inc. 29 | */ 30 | 31 | import { 32 | showToolTip, addTooltipListeners, addThisRowListeners, addFormatListeners, 33 | folder, hide, show, 34 | addScrollListeners, addFolderListeners, addListener 35 | } from "./events"; 36 | import { 37 | findObj, changeFormat, 38 | stripIds, stripUnwanted, delayedHide, getOffset, 39 | getScrollPositions, isIE, benchMark, getZoomFactor, hideToolTip, fadeToolTip, criticalPath, updateFlyingObj, moveToolTip, 40 | } from "./utils/general_utils"; 41 | import { parseXML, parseXMLString, findXMLNode, getXMLNodeValue, AddXMLTask } from './xml'; 42 | import { taskLink, sortTasks, TaskItem, processRows } from "./task"; 43 | import { GanttChart } from "./draw"; 44 | import { parseJSON, parseJSONString, addJSONTask } from "./json"; 45 | import { getMinDate, getMaxDate, parseDateStr, formatDateStr, parseDateFormatStr, getIsoWeek } from "./utils/date_utils"; 46 | 47 | export let JSGantt; if (!JSGantt) JSGantt = {}; 48 | 49 | JSGantt.isIE = isIE; 50 | JSGantt.TaskItem = TaskItem; 51 | JSGantt.GanttChart = GanttChart; 52 | JSGantt.updateFlyingObj = updateFlyingObj; 53 | JSGantt.showToolTip = showToolTip; 54 | 55 | JSGantt.stripIds = stripIds; 56 | JSGantt.stripUnwanted = stripUnwanted; 57 | JSGantt.delayedHide = delayedHide; 58 | 59 | JSGantt.hideToolTip = hideToolTip; 60 | JSGantt.fadeToolTip = fadeToolTip; 61 | JSGantt.moveToolTip = moveToolTip; 62 | 63 | JSGantt.getZoomFactor = getZoomFactor; 64 | 65 | JSGantt.getOffset = getOffset; 66 | JSGantt.getScrollPositions = getScrollPositions; 67 | JSGantt.processRows = processRows; 68 | JSGantt.sortTasks = sortTasks; 69 | 70 | // Used to determine the minimum date of all tasks and set lower bound based on format 71 | JSGantt.getMinDate = getMinDate; 72 | 73 | // Used to determine the maximum date of all tasks and set upper bound based on format 74 | JSGantt.getMaxDate = getMaxDate; 75 | 76 | // This function finds the document id of the specified object 77 | JSGantt.findObj = findObj; 78 | 79 | JSGantt.changeFormat = changeFormat; 80 | 81 | // Tasks 82 | JSGantt.folder = folder; 83 | JSGantt.hide = hide; 84 | JSGantt.show = show; 85 | JSGantt.taskLink = taskLink; 86 | 87 | JSGantt.parseDateStr = parseDateStr; 88 | JSGantt.formatDateStr = formatDateStr; 89 | JSGantt.parseDateFormatStr = parseDateFormatStr; 90 | 91 | // XML 92 | JSGantt.parseXML = parseXML; 93 | JSGantt.parseXMLString = parseXMLString; 94 | JSGantt.findXMLNode = findXMLNode; 95 | JSGantt.getXMLNodeValue = getXMLNodeValue; 96 | JSGantt.AddXMLTask = AddXMLTask; 97 | 98 | // JSON 99 | JSGantt.parseJSON = parseJSON; 100 | JSGantt.parseJSONString = parseJSONString; 101 | JSGantt.addJSONTask = addJSONTask; 102 | 103 | JSGantt.benchMark = benchMark; 104 | JSGantt.getIsoWeek = getIsoWeek; 105 | 106 | JSGantt.addListener = addListener; 107 | JSGantt.addTooltipListeners = addTooltipListeners; 108 | JSGantt.addThisRowListeners = addThisRowListeners; 109 | JSGantt.addFolderListeners = addFolderListeners; 110 | JSGantt.addFormatListeners = addFormatListeners; 111 | JSGantt.addScrollListeners = addScrollListeners; 112 | 113 | JSGantt.criticalPath = criticalPath; 114 | -------------------------------------------------------------------------------- /docs/fixes/general.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | jsGantt Improved 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 20 | 21 | 22 | 23 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Choose a language: 43 | 51 | 52 |
53 | Data getting from a URL, JSON Data 54 | 55 |
56 | 57 | Delay for tooltip to hide (in ms): 58 | 59 |
60 |
61 | 99 |
100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | jsGantt Improved 10 | 11 | 12 | 13 | 22 | 23 | 24 | 26 | 28 | 29 | 30 | 31 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
53 |

Hide and Show Properties

54 | 55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
110 | 111 | 112 |
113 | 114 | Choose a language: 115 | 123 | 124 |
125 | Data getting from a URL, JSON Data 126 | 127 |
128 | 129 | Delay for tooltip to hide (in ms): 130 | 131 | UseSingleCell: 132 | 133 |
134 | * Click events in table are binded to console.log for testing 135 | 136 |
137 |
138 |
139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /docs/fixes/data-plan-color.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pID": 1, 4 | "pName": "Bridge", 5 | "pClass": "ggroupblack", 6 | "pPlanClass": "ggroupblack", 7 | "pGroup": 1, 8 | "pOpen": 1, 9 | "pParent": 0, 10 | "pComp": 0 11 | }, 12 | { 13 | "pID": 2, 14 | "pName": "Preconstruction", 15 | "pClass": "ggroupblack", 16 | "pPlanClass": "ggroupblack", 17 | "pGroup": 1, 18 | "pOpen": 1, 19 | "pParent": 1, 20 | "pComp": 0 21 | }, 22 | { 23 | "pID": 4, 24 | "pName": "Sample Approval", 25 | "pClass": "gtaskred", 26 | "pPlanClass": "gtaskred", 27 | "pGroup": 0, 28 | "pOpen": 1, 29 | "pParent": 2, 30 | "pComp": 0, 31 | "pStart": "2021-06-11T02:00:00.000Z", 32 | "pEnd": "2021-07-02T19:00:00.000Z", 33 | "pPlanStart": "2020-11-20T02:00:00.000Z", 34 | "pPlanEnd": "2020-12-11T19:00:00.000Z", 35 | "pNotes": "Start: 2020-11-20T02:00:00Z -> 2021-06-11T02:00:00Z
\\n End: 2020-12-11T19:00:00Z -> 2021-07-02T19:00:00Z
" 36 | }, 37 | { 38 | "pID": 3, 39 | "pName": "Design and Planning", 40 | "pClass": "gtaskred", 41 | "pPlanClass": "gtaskgreen", 42 | "pGroup": 0, 43 | "pOpen": 1, 44 | "pParent": 2, 45 | "pComp": 0, 46 | "pStart": "2021-03-19T02:00:00.000Z", 47 | "pEnd": "2021-06-10T19:00:00.000Z", 48 | "pPlanStart": "2020-09-01T02:00:00.000Z", 49 | "pPlanEnd": "2020-11-23T19:00:00.000Z", 50 | "pNotes": "Start: 2020-09-01T02:00:00Z -> 2021-03-19T02:00:00Z
\\n End: 2020-11-23T19:00:00Z -> 2021-06-10T19:00:00Z
" 51 | }, 52 | { 53 | "pID": 5, 54 | "pName": "Contract execution -> Contract exection", 55 | "pClass": "gtaskred", 56 | "pPlanClass": "gtaskred", 57 | "pGroup": 0, 58 | "pOpen": 1, 59 | "pParent": 2, 60 | "pComp": 0, 61 | "pStart": "2021-07-05T02:00:00.000Z", 62 | "pEnd": "2021-07-05T19:00:00.000Z", 63 | "pPlanStart": "2020-12-14T02:00:00.000Z", 64 | "pPlanEnd": "2020-12-14T19:00:00.000Z", 65 | "pNotes": "Start: 2020-12-14T02:00:00Z -> 2021-07-05T02:00:00Z
\\n End: 2020-12-14T19:00:00Z -> 2021-07-05T19:00:00Z
" 66 | }, 67 | { 68 | "pID": 6, 69 | "pName": "Construction", 70 | "pClass": "ggroupblack", 71 | "pPlanClass": "ggroupblack", 72 | "pGroup": 1, 73 | "pOpen": 1, 74 | "pParent": 1, 75 | "pComp": 0 76 | }, 77 | { 78 | "pID": 7, 79 | "pName": "Demo", 80 | "pClass": "gtaskred", 81 | "pPlanClass": "gtaskred", 82 | "pGroup": 0, 83 | "pOpen": 1, 84 | "pParent": 6, 85 | "pComp": 0, 86 | "pStart": "2021-06-01T02:00:00.000Z", 87 | "pEnd": "2021-06-01T19:00:00.000Z", 88 | "pPlanStart": "2021-08-25T02:00:00.000Z", 89 | "pPlanEnd": "2021-08-25T19:00:00.000Z", 90 | "pNotes": "Start: 2021-08-25T02:00:00Z -> 2021-06-01T02:00:00Z
\\n End: 2021-08-25T19:00:00Z -> 2021-06-01T19:00:00Z
" 91 | }, 92 | { 93 | "pID": 8, 94 | "pName": "Mobilization", 95 | "pClass": "gtaskred", 96 | "pPlanClass": "gtaskgreen", 97 | "pGroup": 0, 98 | "pOpen": 1, 99 | "pParent": 6, 100 | "pComp": 0, 101 | "pStart": "2021-07-06T02:00:00.000Z", 102 | "pEnd": "2021-08-16T19:00:00.000Z", 103 | "pPlanStart": "2021-07-06T02:00:00.000Z", 104 | "pPlanEnd": "2021-08-16T19:00:00.000Z", 105 | "pNotes": "Start: 2021-09-01T02:00:00Z -> 2021-07-06T02:00:00Z
\\n End: 2021-10-12T19:00:00Z -> 2021-08-16T19:00:00Z
" 106 | }, 107 | { 108 | "pID": 20, 109 | "pName": "Finishes", 110 | "pClass": "gtaskgreen", 111 | "pPlanClass": "gtaskgreen", 112 | "pGroup": 0, 113 | "pOpen": 1, 114 | "pParent": 6, 115 | "pComp": 0, 116 | "pStart": "2022-10-18T02:00:00.000Z", 117 | "pEnd": "2022-11-25T19:00:00.000Z", 118 | "pPlanStart": "2022-01-03T02:00:00.000Z", 119 | "pPlanEnd": "2022-02-10T19:00:00.000Z", 120 | "pNotes": "Start: 2022-01-03T02:00:00Z -> 2022-10-18T02:00:00Z
\\n End: 2022-02-10T19:00:00Z -> 2022-11-25T19:00:00Z
" 121 | }, 122 | { 123 | "pID": 21, 124 | "pName": "Close-out", 125 | "pClass": "ggroupblack", 126 | "pPlanClass": "ggroupblack", 127 | "pGroup": 1, 128 | "pOpen": 1, 129 | "pParent": 1, 130 | "pComp": 0 131 | }, 132 | { 133 | "pID": 22, 134 | "pName": "Punch list", 135 | "pClass": "gtaskgreen", 136 | "pPlanClass": "gtaskgreen", 137 | "pGroup": 0, 138 | "pOpen": 1, 139 | "pParent": 21, 140 | "pComp": 0, 141 | "pStart": "2022-11-28T02:00:00.000Z", 142 | "pEnd": "2022-12-15T19:00:00.000Z", 143 | "pPlanStart": "2022-02-11T02:00:00.000Z", 144 | "pPlanEnd": "2022-03-02T19:00:00.000Z", 145 | "pNotes": "Start: 2022-02-11T02:00:00Z -> 2022-11-28T02:00:00Z
\\n End: 2022-03-02T19:00:00Z -> 2022-12-15T19:00:00Z
" 146 | }, 147 | { 148 | "pID": 23, 149 | "pName": "Final inspections", 150 | "pClass": "gtaskgreen", 151 | "pPlanClass": "gtaskgreen", 152 | "pGroup": 0, 153 | "pOpen": 1, 154 | "pParent": 21, 155 | "pComp": 0, 156 | "pStart": "2022-12-16T02:00:00.000Z", 157 | "pEnd": "2022-12-19T19:00:00.000Z", 158 | "pPlanStart": "2022-03-03T02:00:00.000Z", 159 | "pPlanEnd": "2022-03-04T19:00:00.000Z", 160 | "pNotes": "Start: 2022-03-03T02:00:00Z -> 2022-12-16T02:00:00Z
\\n End: 2022-03-04T19:00:00Z -> 2022-12-19T19:00:00Z
" 161 | }, 162 | { 163 | "pID": 24, 164 | "pName": "Close-out documents", 165 | "pClass": "gtaskgreen", 166 | "pPlanClass": "gtaskgreen", 167 | "pGroup": 0, 168 | "pOpen": 1, 169 | "pParent": 21, 170 | "pComp": 0, 171 | "pStart": "2022-12-20T02:00:00.000Z", 172 | "pEnd": "2023-01-06T19:00:00.000Z", 173 | "pPlanStart": "2022-03-07T02:00:00.000Z", 174 | "pPlanEnd": "2022-03-24T19:00:00.000Z", 175 | "pNotes": "Start: 2022-03-07T02:00:00Z -> 2022-12-20T02:00:00Z
\\n End: 2022-03-24T19:00:00Z -> 2023-01-06T19:00:00Z
" 176 | } 177 | ] -------------------------------------------------------------------------------- /docs/demobigdata.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | jsGantt Improved 10 | 11 | 12 | 13 | 22 | 23 | 24 | 26 | 28 | 29 | 30 | 31 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 |

Hide and Show Properties

52 | 53 |
54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
113 | 114 | 115 |
116 | 117 | Choose a language: 118 | 131 | 132 |
133 | Data getting from a URL, JSON Data. Use `bigdata.json` to test with more data. 134 | 135 |
136 | 137 | Delay for tooltip to hide (in ms): 138 | 139 | UseSingleCell: 140 | 141 |
142 | * Click events in table are binded to console.log for testing 143 | 144 |
145 | 146 | 147 | 148 | 149 | 150 | 151 |
152 | 153 | 154 | 155 | 156 | 157 | 158 |
159 |
160 |
161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/jsGanttImproved/jsgantt-improved.svg?branch=master)](https://travis-ci.com/jsGanttImproved/jsgantt-improved) 2 | 3 | 4 | A fully featured gantt chart component built entirely in Javascript, CSS and AJAX. It is lightweight and there is no need of external libraries or additional images. 5 | 6 | 7 | ![Demo Image](/docs/demo.gif) 8 | 9 | 10 | Start using with including the files `jsgantt.js` and `jsgantt.css` that are inside `dist/` folder. 11 | 12 | Or install and use in JS 13 | 14 | `npm install jsgantt-improved` 15 | 16 | Import in your JS `import {JSGantt} from 'jsgantt-improved';` 17 | 18 | See the [FULL DOCUMENTATION](./Documentation.md) for more details in all features. 19 | 20 | For **Angular** use the component [ng-gantt](https://github.com/jsGanttImproved/ng-gantt) 21 | 22 | For **React** use the component [react-jsgantt](https://github.com/jsGanttImproved/react-jsgantt) 23 | 24 | For **Vue** , see this example: https://stackblitz.com/edit/vue-jsgantt-3 25 | 26 | For **.NET** , see this example: [.NET Documentation](./docs/DotNet.md) 27 | 28 | 29 | ## Example 30 | 31 | 32 | You can view a Solo live example at: 33 | 34 | * https://jsganttimproved.github.io/jsgantt-improved/docs/demo.html 35 | 36 | Or use a live coding example at Codenpen: 37 | 38 | * https://codepen.io/mariomol/pen/mQzBPV 39 | 40 | 41 | ## Easy to Use 42 | 43 | ```html 44 | 45 | 46 | 47 |
48 | 49 | 105 | ``` 106 | 107 | ## Features 108 | 109 | * Tasks & Collapsible Task Groups 110 | * Dependencies and Highlight when hover a task 111 | * Edit data in gantt table with list of responsible 112 | * Task Completion 113 | * Table with Additional Columns 114 | * Task Styling or as HTML tags 115 | * Milestones 116 | * Resources 117 | * Costs 118 | * Plan Start and End Dates 119 | * Gantt with Planned vs Executed 120 | * Dynamic Loading of Tasks 121 | * Dynamic change of format: Hour, Day, Week, Month, Quarter 122 | * Load Gantt from JSON and XML 123 | * From external files (including experimental support for MS Project XML files) 124 | * From JavaScript Strings 125 | 126 | ### Internationalization 127 | 128 | Support for languages below: 129 | 130 | * Arabic (ar) 131 | * Chinese (cn) 132 | * Czech (cs) 133 | * Dutch (Standard) 134 | * English (en) 135 | * French (fr) 136 | * Finnish (fi) 137 | * German (de) 138 | * Hebrew (he) 139 | * Hungarian (hu) 140 | * Korean (ko) 141 | * Indonesian (id) 142 | * Italian (it) 143 | * Japanese (ja) 144 | * Portuguese (pt) 145 | * Polish (pl) 146 | * Russian (ru) 147 | * Spanish (es) 148 | * Swedish (sv) 149 | * Turkish (tr) 150 | * Ukraininan (ua) 151 | 152 | ## Documentation 153 | 154 | See the [Documentation](./Documentation.md) wiki page or the included ``docs/index.html`` file for instructions on use. 155 | 156 | Project based on https://code.google.com/p/jsgantt/. 157 | 158 | 159 | ## Want to Collaborate? 160 | 161 | Its easy to get it set: 162 | 163 | * Clone this repo 164 | * Install lib dependencies: `npm i` 165 | * Install global dependencies: `npm i -g browserify nodemon onchange tsc` 166 | * Compile final js to be used on demo: `npm run dist` 167 | * Run the demo with a live example: `npm start`. 168 | * You can check the demo gantt that we use for testing features at: `http://127.0.0.1:8080/docs/demo.html` 169 | * Use `npm run watch` or do your change in `src` and restart this command refresh the changes. 170 | 171 | For testing: 172 | * Install global dependencies: `npm i -g webdriver-manager` 173 | * Install selenium webdriver: `npm run webdriver`, it will install something like node_modules/webdriver-manager/selenium/chromedriver_88.0.4324.96.zip 174 | 175 | node node_modules/protractor/bin/webdriver-manager update 176 | apt install chromium 177 | 178 | apt install chromium-bsu 179 | 180 | * Use `npm run test` with e2e tests. 181 | * Or use `npm run watch:test` to keep watching the tests 182 | 183 | For new release: 184 | * Increment the version number on package.json 185 | * Run `npm run publishnpm` 186 | 187 | 188 | Or help us donating... 189 | 190 | [![](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=S7B43P63C5QEN) 191 | 192 | 193 | -------------------------------------------------------------------------------- /src/utils/draw_utils.ts: -------------------------------------------------------------------------------- 1 | import { addFormatListeners } from "../events"; 2 | 3 | export const makeInput = function (formattedValue, editable, type = 'text', value = null, choices = null) { 4 | if (!value) { 5 | value = formattedValue; 6 | } 7 | if (editable) { 8 | switch (type) { 9 | case 'date': 10 | // Take timezone into account before converting to ISO String 11 | value = value ? new Date(value.getTime() - (value.getTimezoneOffset() * 60000)).toISOString().split('T')[0] : ''; 12 | return ``; 13 | case 'resource': 14 | if (choices) { 15 | const found = choices.filter(c => c.id == value || c.name == value); 16 | if (found && found.length > 0) { 17 | value = found[0].id; 18 | } else { 19 | choices.push({ id: value, name: value }); 20 | } 21 | return ``; 22 | } else { 23 | return ``; 24 | } 25 | case 'cost': 26 | return ``; 27 | default: 28 | return ``; 29 | } 30 | } else { 31 | return formattedValue; 32 | } 33 | } 34 | 35 | export const newNode = function (pParent, pNodeType, pId = null, pClass = null, pText = null, 36 | pWidth = null, pLeft = null, pDisplay = null, pColspan = null, pAttribs = null) { 37 | let vNewNode = pParent.appendChild(document.createElement(pNodeType)); 38 | if (pAttribs) { 39 | for (let i = 0; i + 1 < pAttribs.length; i += 2) { 40 | vNewNode.setAttribute(pAttribs[i], pAttribs[i + 1]); 41 | } 42 | } 43 | if (pId) vNewNode.id = pId; // I wish I could do this with setAttribute but older IEs don't play nice 44 | if (pClass) vNewNode.className = pClass; 45 | if (pWidth) vNewNode.style.width = (isNaN(pWidth * 1)) ? pWidth : pWidth + 'px'; 46 | if (pLeft) vNewNode.style.left = (isNaN(pLeft * 1)) ? pLeft : pLeft + 'px'; 47 | if (pText) { 48 | if (pText.indexOf && pText.indexOf('<') === -1) { 49 | vNewNode.appendChild(document.createTextNode(pText)); 50 | } else { 51 | vNewNode.insertAdjacentHTML('beforeend', pText); 52 | } 53 | } 54 | if (pDisplay) vNewNode.style.display = pDisplay; 55 | if (pColspan) vNewNode.colSpan = pColspan; 56 | return vNewNode; 57 | }; 58 | 59 | 60 | 61 | export const getArrayLocationByID = function (pId) { 62 | let vList = this.getList(); 63 | for (let i = 0; i < vList.length; i++) { 64 | if (vList[i].getID() == pId) 65 | return i; 66 | } 67 | return -1; 68 | }; 69 | 70 | export const CalcTaskXY = function () { 71 | let vID; 72 | let vList = this.getList(); 73 | let vBarDiv; 74 | let vTaskDiv; 75 | let vParDiv; 76 | let vLeft, vTop, vWidth; 77 | let vHeight = Math.floor((this.getRowHeight() / 2)); 78 | 79 | for (let i = 0; i < vList.length; i++) { 80 | vID = vList[i].getID(); 81 | vBarDiv = vList[i].getBarDiv(); 82 | vTaskDiv = vList[i].getTaskDiv(); 83 | if ((vList[i].getParItem() && vList[i].getParItem().getGroup() == 2)) { 84 | vParDiv = vList[i].getParItem().getChildRow(); 85 | } 86 | else vParDiv = vList[i].getChildRow(); 87 | 88 | if (vBarDiv) { 89 | vList[i].setStartX(vBarDiv.offsetLeft + 1); 90 | vList[i].setStartY(vParDiv.offsetTop + vBarDiv.offsetTop + vHeight - 1); 91 | vList[i].setEndX(vBarDiv.offsetLeft + vBarDiv.offsetWidth + 1); 92 | vList[i].setEndY(vParDiv.offsetTop + vBarDiv.offsetTop + vHeight - 1); 93 | } 94 | } 95 | }; 96 | 97 | export const sLine = function (x1, y1, x2, y2, pClass) { 98 | let vLeft = Math.min(x1, x2); 99 | let vTop = Math.min(y1, y2); 100 | let vWid = Math.abs(x2 - x1) + 1; 101 | let vHgt = Math.abs(y2 - y1) + 1; 102 | 103 | let vTmpDiv = document.createElement('div'); 104 | vTmpDiv.id = this.vDivId + 'line' + this.vDepId++; 105 | vTmpDiv.style.position = 'absolute'; 106 | vTmpDiv.style.overflow = 'hidden'; 107 | vTmpDiv.style.zIndex = '0'; 108 | vTmpDiv.style.left = vLeft + 'px'; 109 | vTmpDiv.style.top = vTop + 'px'; 110 | vTmpDiv.style.width = vWid + 'px'; 111 | vTmpDiv.style.height = vHgt + 'px'; 112 | 113 | vTmpDiv.style.visibility = 'visible'; 114 | 115 | if (vWid == 1) vTmpDiv.className = 'glinev'; 116 | else vTmpDiv.className = 'glineh'; 117 | 118 | if (pClass) vTmpDiv.className += ' ' + pClass; 119 | 120 | this.getLines().appendChild(vTmpDiv); 121 | 122 | if (this.vEvents.onLineDraw && typeof this.vEvents.onLineDraw === 'function' ) { 123 | this.vEvents.onLineDraw(vTmpDiv); 124 | } 125 | 126 | return vTmpDiv; 127 | }; 128 | 129 | export const drawSelector = function (pPos) { 130 | let vOutput = document.createDocumentFragment(); 131 | let vDisplay = false; 132 | 133 | for (let i = 0; i < this.vShowSelector.length && !vDisplay; i++) { 134 | if (this.vShowSelector[i].toLowerCase() == pPos.toLowerCase()) vDisplay = true; 135 | } 136 | 137 | if (vDisplay) { 138 | let vTmpDiv = newNode(vOutput, 'div', null, 'gselector', this.vLangs[this.vLang]['format'] + ':'); 139 | 140 | if (this.vFormatArr.join().toLowerCase().indexOf('hour') != -1) 141 | addFormatListeners(this, 'hour', newNode(vTmpDiv, 'span', this.vDivId + 'formathour' + pPos, 'gformlabel' + ((this.vFormat == 'hour') ? ' gselected' : ''), this.vLangs[this.vLang]['hour'])); 142 | 143 | if (this.vFormatArr.join().toLowerCase().indexOf('day') != -1) 144 | addFormatListeners(this, 'day', newNode(vTmpDiv, 'span', this.vDivId + 'formatday' + pPos, 'gformlabel' + ((this.vFormat == 'day') ? ' gselected' : ''), this.vLangs[this.vLang]['day'])); 145 | 146 | if (this.vFormatArr.join().toLowerCase().indexOf('week') != -1) 147 | addFormatListeners(this, 'week', newNode(vTmpDiv, 'span', this.vDivId + 'formatweek' + pPos, 'gformlabel' + ((this.vFormat == 'week') ? ' gselected' : ''), this.vLangs[this.vLang]['week'])); 148 | 149 | if (this.vFormatArr.join().toLowerCase().indexOf('month') != -1) 150 | addFormatListeners(this, 'month', newNode(vTmpDiv, 'span', this.vDivId + 'formatmonth' + pPos, 'gformlabel' + ((this.vFormat == 'month') ? ' gselected' : ''), this.vLangs[this.vLang]['month'])); 151 | 152 | if (this.vFormatArr.join().toLowerCase().indexOf('quarter') != -1) 153 | addFormatListeners(this, 'quarter', newNode(vTmpDiv, 'span', this.vDivId + 'formatquarter' + pPos, 'gformlabel' + ((this.vFormat == 'quarter') ? ' gselected' : ''), this.vLangs[this.vLang]['quarter'])); 154 | } 155 | else { 156 | newNode(vOutput, 'div', null, 'gselector'); 157 | } 158 | return vOutput; 159 | }; 160 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to jsGanttImproved 2 | 3 | We'd love for you to contribute to our source code and to make jsGanttImproved even better than it is 4 | today! Here are the guidelines we'd like you to follow: 5 | 6 | - [Issues and Bugs](#issue) 7 | - [Feature Requests](#feature) 8 | - [Submission Guidelines](#submit) 9 | - [Coding Rules](#rules) 10 | - [Commit Message Guidelines](#commit) 11 | - [Further Info](#info) 12 | 13 | ## Found an Issue? 14 | 15 | If you find a bug in the source code or a mistake in the documentation, you can help us by 16 | submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request 17 | with a fix. 18 | 19 | **Please see the [Submission Guidelines](#submit) below.** 20 | 21 | ## Want a Feature? 22 | 23 | You can request a new feature by submitting an issue to our [GitHub Repository][github]. If you 24 | would like to implement a new feature then it can be crafted and submitted as a Pull Request. 25 | 26 | ## Submission Guidelines 27 | 28 | ### Submitting an Issue 29 | Before you submit your issue search the archive, maybe your question was already answered. 30 | 31 | If your issue appears to be a bug, and hasn't been reported, open a new issue. Help us to maximize 32 | the effort we can spend fixing issues and adding new features, by not reporting duplicate issues. 33 | Providing the following information will increase the chances of your issue being dealt with 34 | quickly: 35 | 36 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps 37 | * **Motivation for or Use Case** - explain why this is a bug for you 38 | * **Version(s)** - what is the version(s) being used? 39 | * **Browsers and Operating System** - is this a problem with all browsers or only specific ones? 40 | * **Reproduce the Error** - provide a live example (using [Plunker][plunker] or 41 | [JSFiddle][jsfiddle]) or an unambiguous set of steps. 42 | * **Related Issues** - has a similar issue been reported before? 43 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 44 | causing the problem (line of code or commit) 45 | 46 | ### Submitting a Pull Request 47 | Before you submit your pull request consider the following guidelines: 48 | 49 | * Search [GitHub](https://github.com/jsGanttImproved/jsgantt-improved/pulls) for an open or closed Pull Request 50 | that relates to your submission. You don't want to duplicate effort. 51 | * Make your changes in a new git branch: 52 | 53 | ```shell 54 | git checkout -b my-fix-branch master 55 | ``` 56 | 57 | * Create your patch. 58 | * Follow our [Coding Rules](#rules). 59 | * Commit your changes using a descriptive commit message that follows our 60 | [commit message conventions](#commit). 61 | 62 | ```shell 63 | git commit -a 64 | ``` 65 | Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files. 66 | 67 | * Push your branch to GitHub: 68 | 69 | ```shell 70 | git push origin my-fix-branch 71 | ``` 72 | 73 | In GitHub, send a pull request to `master`. 74 | If we suggest changes, then: 75 | 76 | * Make the required updates. 77 | * Commit your changes to your branch (e.g. `my-fix-branch`). 78 | * Push the changes to your GitHub repository (this will update your Pull Request). 79 | 80 | If the PR gets too outdated we may ask you to rebase and force push to update the PR: 81 | 82 | ```shell 83 | git rebase master -i 84 | git push origin my-fix-branch -f 85 | ``` 86 | 87 | _WARNING: Squashing or reverting commits and force-pushing thereafter may remove GitHub comments 88 | on code that were previously made by you or others in your commits. Avoid any form of rebasing 89 | unless necessary._ 90 | 91 | That's it! Thank you for your contribution! 92 | 93 | #### After your pull request is merged 94 | 95 | After your pull request is merged, you can safely delete your branch and pull the changes 96 | from the main (upstream) repository: 97 | 98 | * Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows: 99 | 100 | ```shell 101 | git push origin --delete my-fix-branch 102 | ``` 103 | 104 | * Check out the master branch: 105 | 106 | ```shell 107 | git checkout master -f 108 | ``` 109 | 110 | * Delete the local branch: 111 | 112 | ```shell 113 | git branch -D my-fix-branch 114 | ``` 115 | 116 | * Update your master with the latest upstream version: 117 | 118 | ```shell 119 | git pull --ff upstream master 120 | ``` 121 | 122 | ## Coding Rules 123 | 124 | To ensure consistency throughout the source code, keep these rules in mind as you are working: 125 | 126 | * With the exceptions listed below, we follow the rules contained in 127 | [Google's JavaScript Style Guide][js-style-guide]: 128 | * Wrap all code at **100 characters**. 129 | 130 | ## Git Commit Guidelines 131 | 132 | We have very precise rules over how our git commit messages can be formatted. This leads to **more 133 | readable messages** that are easy to follow when looking through the **project history**. 134 | 135 | ### Commit Message Format 136 | Each commit message consists of a **subject**, a **body** and a **footer**: 137 | 138 | ``` 139 | 140 | 141 | 142 | 143 |