Auto-resizing custom column input fields in GanttChartView component for JavaScript

A short one today. This is how you can ensure the input (or other HTML element) of your custom column cell template would automatically be resized when the end user changes the width of the grid column, such as by dragging its grip horizontally:

  1. Define a variable to hold the column object itself.
  2. In your custom cellTemplate function refer to column.width when you create the input element (or, if you reuse an input, update its style width); 16px should be left for separator margins.
  3. Add the custom column to the columns collection within settings, as usual.
var columns = DlhSoft.Controls.GanttChartView.getDefaultColumns(items, settings);
var myColumn1 = { 
  header: 'My value 1', width: 80, 
  cellTemplate: function (item) { 
    return DlhSoft.Controls.GanttChartView.textInputColumnTemplateBase(
      document, Math.max(0, myColumn1.width - 16), 
      function () { return item.myValue1; }, 
      function (value) { item.myValue1 = value; }); } };
columns.push(myColumn1);
settings.columns = columns;

Advertisement
Posted in Development Components | Tagged , , , , | Leave a comment

Displaying and creating Schedule chart dependencies with Gantt Chart Light Library components

We’ve just updated the Schedule chart components (ScheduleChartView and ScheduleChartDataGrid) from Gantt Chart Light Library, adding support for showing and creating dependency lines between chart bars:

To display the dependencies, simply ensure you add PredecessorItem objects into the successors’ Predecessors collections, pointing to the predecessor GanttChartItem objects and optionally indicating the dependency types:

var items = new ObservableCollection<ScheduleChartItem>
{
    new ScheduleChartItem { Content = "Resource 1", … },
    new ScheduleChartItem { Content = "Resource 2", … },
    …
};
items[0].GanttChartItems
  .Add(new GanttChartItem { Content = "Task 1", 
                            Start = new DateTime(…),
                            Finish = new DateTime(…), … });
items[0].GanttChartItems
  .Add(new GanttChartItem { Content = "Task 2",
                            Start = new DateTime(…),
                            Finish = new DateTime(…), … });
items[1].GanttChartItems
  .Add(new GanttChartItem { Content = "Task 3",
                            Start = new DateTime(…),
                            Finish = new DateTime(…), … });
…
items[0].GanttChartItems[1].Predecessors
  .Add(new PredecessorItem { Item = items[0].GanttChartItems[0] });
items[1].GanttChartItems[0].Predecessors
  .Add(new PredecessorItem { Item = items[0].GanttChartItems[1] });
…
ScheduleChartDataGrid.Items = items;

To allow the end user to create dependencies himself or herself, you need to supplement the initialization code above with setting the DependencyCreationValidator closure, for example as below to allow dependencies between any different items in the chart:

ScheduleChartDataGrid.DependencyCreationValidator = 
  (item1, item2) => item1 != item2;

Enjoy!

Posted in Development Components | Tagged , , , | Leave a comment

Licensing DlhSoft’s .NET and JavaScript components – TL;DR

OK. Sorry. TL;DR is not really possible on this topic. You can however, jump to the final paragraphs for some (possibly) simpler (or required) alternatives to classic .NET licensing.


Once you purchase a development library license from DlhSoft, you will receive an XML file. You then install it for the software package (downloaded separately, e.g. previously, for trying out the components) and apply it to your development project.

The XML license file is all you need to make the trial nag screens go away. Because Microsoft licensing is complex, however, for the .NET Framework software you will need to follow a few steps to apply the license. These steps also depend on the way you have installed the software package in the first place (Setup, NuGet package, received it with cloning of a folder).

Assuming that you are using NuGet packages, that you are working on a Windows machine, and that you want to use DlhSoft License Manager – a tool that we provide to help you setup the license file with more ease, follow these steps:

  • Using Windows Explorer, go to your solution folder, then to this subfolder: packages\DlhSoft.[product].[version]\lib\[target]. For example: [product] = GanttChartWebLibrary, [version] = 5.3.3, [target] = net45 (you will need to know what .NET version your project targets, and select the appropriate target subfolder within lib there);
  • Extract LicenseManagement.zip file into a LicenseManagement subfolder: packages\DlhSoft.[product].[version]\lib\[target]\LicenseManagement;
  • Run the License Manager tool by starting this executable file (signed by DLHSOFT SRL): packages\DlhSoft.[product].[version]\lib\[target]\LicenseManagement\LicenseManager.exe.
  • In the License Manager tool, use Install link and select the XML file you have received. This will generate LIC files for individual components of the package in the same folder with the DLLs that Visual Studio will eventually use to license the components.
  • But for Visual Studio to know which are the licensable components, a Licenses.licx file is also needed in your project. That is a simple text file, listing the .NET components with their assemblies. The License Manager tool can create/update the Licenses.licx file for you. Click Apply license link (after installation succeeded) and select the .csproj or .vbproj that you are working on (the executable one, if you have more project in a Visual Studio solution).

For JavaScript, things are similar but [target] will be simply “Javascript”. Moreover, the Apply link will not require a Visual Studio project, but will give you the lines of code that you should just copy and paste to be run somewhere in your app’s initialization section instead.

For .NET Framework licensing an (arguably) simpler alternative to all the steps above is to just call a SetLicense method for each component that you use, somewhere in your app’s initialization code, passing the entire XML as a string argument (ensuring you properly escape characters, if needed). You’ll find SetLicenses static method in a special namespace; the call will eventually be formed like this: DlhSoft.[Namespace].Licensing.[ComponentName].SetLicense(““).

Finally, for .NET Core and .NET 5 the SetLicense alternative is actually required (as the classic NET Framework licensing is not supported anymore.)

Let us know if you need more details or if yoy have any further questions about any of the steps by contacting DlhSoft Support.

Thank you for your interest!


You may read more technical details about Dlhsoft component licensing (and see a diagram guiding you through the process) here.

Posted in Development Components | Tagged | Leave a comment

Exporting JavaScript-based Gantt chart content as SVG and PNG

All JavaScript-based components from Gantt Chart Hyper Library (and, through their client counterparts, as well those .NET 4 and .NET Core/5-based ones from Gantt Chart Web Library) allow you to either print or export content.

Printing actually uses content exporting – since that simply creates a new HTML document in a new window which can then be sent as content to the browser’s printing mechanism.

But sometimes HTML is not good enough. End users might want to get a SVG drawing or a PNG bitmap out of some Gantt chart content rather than just exposing it as HTML in a new browser tab or “printing” it as a PDF (or, why not, sending it to a real printer).

While there’s no built-in SVG/PNG export feature yet, such a feature can be easily added to a Web app by using some modern development techniques, too. Here is a comment-based guide to accomplish both SVG and PNG exporting with custom code:

function exportPng() {
    // Prepare a temporary window to export content to.
    var exportWindow = window.open('', '_blank', 'width=320,height=100,' +
        'location=no,menubar=no,toolbar=no,status=no,scrollbars=yes'), 
        exportElement = exportWindow.document.body;
    // Configure the output document's body for imaging purposes.
    exportElement.style.backgroundColor = 'white';
    exportElement.style.margin = '0';
    // Export the Gantt Chart (ganttChartView component) using the provided
    // options:
    ganttChartView.exportContent(
        { title: 'Gantt Chart (exported)', isGridVisible: true,
          columnIndexes: [1], timelineStart: new Date(year, month, 1), 
          timelineFinish: new Date(new Date(year, month, 1).valueOf() 
              + 5 * 7 * 24 * 60 * 60 * 1000), preparingMessage: '...' },
        exportWindow);
    // Continue after exporting the content finishes.
    setTimeout(function() {
        // Determine the size needed by the exported image.
        var width = exportElement.scrollWidth, 
            height = exportElement.scrollHeight;
        // Prepare SVG image data URL, initializing an XML-based document of SVG
        // type, with a foreighObject container that inlucdes full, valid XHTML
        // for the exported object.
        var dataUrl = 'data:image/svg+xml;charset=utf-8,' + 
            '<svg xmlns="http://www.w3.org/2000/svg" ' + 
                'width="' + width + '" height="' + height + '">' +
                '<foreignObject x="0" y="0" width="100%" height="100%">' + 
                    new XMLSerializer().serializeToString(exportElement)
                        .replace(/#/g, '%23').replace(/\n/g, '%0A') + 
                '</foreignObject>' + 
            '</svg>';

        // Prepare a temporary image element to display the SVG content.
        var image = new Image();
        image.src = dataUrl;
        // Continue after the image is loaded.
        setTimeout(function() {
            // Prepare a temporary canvas and have the image drawn into it 
            // (using a specific scale to ensure required output DPI/quality).
            var canvas = document.createElement('canvas');
            var scale = 2;
            canvas.width = width * scale;
            canvas.height = height * scale;
            canvas.getContext('2d')
                .drawImage(image, 0, 0, width * scale, height * scale);

            // Provide the content of the canvas as data URL and request client 
            // side downloading.
            var link = document.createElement('a');
            link.download = 'Gantt-export.png';
            link.href = canvas.toDataURL();
            link.click();
            // Close the export window.
            exportWindow.close();    
        });
    });
}

Here are two full export image sample apps with full source code (check export* functions within app.js files): one for exporting SVG, and another one for exporting PNG.

Posted in Development Components | Tagged , , , , | Leave a comment

Importing and exporting task data from GanttChartDataGrid as (Excel-supported) tab delimited text files

Fotografie de freestocks.org pe Pexels.com

GanttChartDataGrid component from DlhSoft Gantt Chart Light Library allows developers to set up and display an interactive Gantt chart in their WPF app. But how can they allow end users to export and import task items to and from Excel, one might ask?

Let’s observe first that to copy data from the Gantt chart’s data grid the end user can directly use the Copy command (if exposed by the developer) to save the contents to the clipboard in that specific format. So they can easily paste values directly into an Excel file. (And back, with Paste command of GanttChartDataGrid as well.)

GanttChartDataGrid.SelectAll();
GanttChartDataGrid.Copy();
...
GanttChartDataGrid.Paste();

But Excel also supports tab-delimited text files as input (and output) for single sheet documents. Developers have therefore an alternative through that path, too: they can allow end users to select the tasks that they want to export (or select all tasks, if needed, instead) and get the tab-delimited string output placed into a text file of user’s choice. The latter can then load it in Excel with ease:

using (Stream stream = saveFileDialog.OpenFile())
{
    using (StreamWriter writer = new StreamWriter(stream))
    {
        var data = GanttChartDataGrid.GetCopy(); // tab delimited text formatted
        writer.Write(data);
    }
}

To import data back from tab delimited text files saved from Excel into GanttChartDataGrid, however, things are a bit more tricky. The full sample app with source code is available here. Check MainWindow.xaml.cs inside, and here you go: your users will be able to import/export task items with a lot more ease!

Posted in Miscellaneous | Tagged , , , , , | Leave a comment

ASP .NET Core demos for Gantt Chart Web Library (MVC)

Gantt Chart Web Library was a classic .NET Framework package (WebForms first, then MVC as well) until .NET Core 2.1 became available. Since then, however, we’ve also created .NET Core extensions that leverage the same underlying JavaScript components as the original views used (available, by the way. as standalone browser widgets with Gantt Chart Hyper Library, too).

But until today we haven’t had a showcase app to show all main features that the .NET Core components would be able to offer. You had to check out our classic ASP .NET WebForms demos first and convert and adapt their source there to .NET Core and MVC patterns, yourself.

You’ve asked us to create a “Main features”-like sample app showing how developers can allow end users to add and remove tasks, increase and decrease indentation, set up colors, highlight critical path, auto-schedule and level resources for tasks presented in a Gantt Chart view, or even show other views using the same project data (Schedule Chart, Load Chart, PERT Chart and Network Diagram) – so here we go:

We’ve just published this new live .NET Core 3.1 demo with full reference source code on GitHub for you to check out and enjoy! (More samples should come later, too.)

Posted in Development Components | Tagged , , , | Leave a comment

Aligning expander buttons for Gantt chart items when using recent versions of Bootstrap and DlhSoft Gantt Chart Hyper/Web Library

We’ve just noticed that recent versions of Bootstrap inject the following CSS to Web applications (at least under ASP .NET Core MVC projects created from Visual Studio):

svg {
  vertical-align: middle;
}

This may lead to our component showing the expander triangle buttons for Gantt chart items improperly aligned vertically: they are shown centered on the baseline of the text, rather than above it.

To fix the issue, you would simply need to reset the vertical-align setting from your CSS:

svg {
  vertical-align: initial;
}

We’ll also try to address this internally (so you won’t need to do anything afterwards) with a future product update, but until then please use the workaround above.

Posted in Development Components | Tagged , , , , | Leave a comment

Initializing JavaScript GanttChartView component items with start and effort (rather than finish)

If you have tried GanttChartView from Gantt Chart Hyper Library you have probably seen that our component requires initializing items using start and finish date values. (This is in attempt to ensure things are as optimized as possible by default, avoding computations whenever not needed.)

However, if your data source doesn’t store the finish dates at all (so you don’t have such input values), but just items’ start and effort instead, you can still use our component! You need to compute the required finish values at initialization time, yourself. But don’t worry, we’ve still got your back: we offer a “static” getFinish function that may help you with this, too.

Because it is a more “internal” function, though, it does have some important requirements itself: you need to prepare its settings argument in a specific way, with workingWeekStart and -Finish, and visibleDayStart and -Finish fields (note that the Gantt Chart component would generally support different working and visible week intervals, but not day intervals, thus the field name difference), plus an optional specialNonworkingDays array with dates set up as UTC input, with 00:00 time values; you can use getInputDate/getOutputDate functions to convert the dates as needed, and this is true for start and finish arguments, as well:

var GanttChartView = DlhSoft.Controls.GanttChartView;
var specialSettings = {
  workingWeekStart: 1, // Monday
  workingWeekFinish: 5, // Friday
  visibleDayStart: 8 * 60 * 60 * 1000, // 8 AM
  visibleDayFinish: 16 * 60 * 60 * 1000, // 4 PM
  specialNonworkingDays: [
    GanttChartView.getInputDate(new Date(2020, 4-1, 28))] // April 28 is a day off
};
// Known start and effort:
var start = GanttChartView.getInputDate(new Date(2020, 4-1, 27, 8, 0, 0)); // Starting on April 27
var effort = 2.75 * 8 * 60 * 60 * 1000;  // Duration: 2.75 working days
// Compute finish:
var finish = GanttChartView.getOutputDate(
  GanttChartView.getFinish(start, effort, specialSettings));
// Use finish (e.g. initializing item based on start and finish):
alert(finish); // April 30, 14:00 (not April 29, since 28 was a day off!)
Posted in Development Components | Tagged , , , , , , | Leave a comment

Auto-save upon client side changes with GanttChartView for ASP .NET WebForms

If you are (still) using our ASP .NET WebForms-based Gantt Chart components and you need automatic postbacks to the server whenever the end users perform changes on the client side, e.g. to save them to a central database, don’t worry, you’re NOT out of luck: a Save button (triggering “manual” postbacks) isn’t mandatory, although in our opinion the latter would still be the preferred solution from an experience point of view: it would allow people decide when and whether the changes should be actually submitted, and the user interface wouldn’t be refreshed until that time, either.

However, to simply submit the ASP .NET form to the server whenever item changes occur, you can use a snipper like the one presented below. Trying to partially mitigate the downsides described above, we set up some auto-increasing delay for an end user to be able to complete multiple updates before triggering the auto-save postback (to minimize workload, traffic, and à la WebForms interface refreshes too):

// Assumes GanttChartView is declared within a form with id='form1' and runat='server'.
GanttChartView.ItemPropertyChangeHandlerClientCode = @"
  if (isDirect && isFinal)
    var form = document.getElementById('form1');
    if (form.postbackTimeout)
      clearTimeout(form.postbackTimeout);
    form.postbackTimeout = setTimeout(function() { 
      form.submit();
      delete form.postbackTimeout;
    }, 5000); // auto-increasing 5 seconds delay
}";

Enjoy!

Posted in Development Components | Tagged , , , , | Leave a comment

Formatting dates on custom date columns with Gantt Chart Hyper Library

If you try to combine our Custom columns sample app for Gantt Chart Hyper Library – specifically, the baseline start and finish columns –  with Custom date formatters (or you simply want to define custom date-time fields on your items and then display and allow editing their value using specifically added columns), you might find out that the dates are not formatted as you would expect (as the main start and finish dates are.)

To resolve this issue you can use a workaround, though. You need to define a custom date input template that does format the value using settings.dateTimeFormatter (and reads values from the associated input element using dateTimeParser too), and then map it to baselineStart and baselineFinish (or any other custom date-time) fields as follows:

function formattedDateTimeInputColumnTemplateBase(document, width, valueGetter, valueSetter, isEnabledGetter, isVisibleGetter, isBoldGetter) {
    return DlhSoft.Controls.GanttChartView.textInputColumnTemplateBase(document, width,
        function () {
            var value = valueGetter();
            if (value != null)
                return settings.dateTimeFormatter(value);
            return "";
        },
        function (value) {
            if (value != "")
                value = DlhSoft.Controls.GanttChartView.dateTimeParser(value);
            else
                value = null;
            valueSetter(value);
        },
        isEnabledGetter, isVisibleGetter, isBoldGetter
    );
};
function formattedBaselineStartColumnTemplate(inputWidth) {
    return function (item) {
        var ganttChartView = item.ganttChartView, document = ganttChartView.ownerDocument;
        return formattedDateTimeInputColumnTemplateBase(document, inputWidth,
            function () {
                return item.baselineStart;
            },
            function (value) {
                if (value != null)
                    item.baselineStart = value;
                else
                    delete item.baselineStart;
                ganttChartView.onItemPropertyChanged(item, "baselineStart", true, true);
                ganttChartView.refreshItem(item);
            },
            function () { return !(item.isReadOnly || (typeof item.ganttChartView !== "undefined" && typeof item.ganttChartView.settings !== "undefined" && (item.ganttChartView.settings.isReadOnly || item.ganttChartView.settings.isGridReadOnly))); },
            function () { return !(typeof item.isBarVisible !== "undefined" && !item.isBarVisible); },
            function () { return (item.hasChildren && (typeof item.isSummaryEnabled === "undefined" || item.isSummaryEnabled)); }
        );
    }
};
function formattedBaselineFinishColumnTemplate(inputWidth) {
    ...
};
// cellTemplate fields use the functions declared above:
columns.push({ header: 'Plan Start', width: 140, cellTemplate: formattedBaselineStartColumnTemplate(124) });
columns.push({ header: 'Plan End', width: 140, cellTemplate: formattedBaselineFinishColumnTemplate(124) });

We hope it helps. Enjoy!

Posted in Development Components | Tagged , , , , , , | Leave a comment