Multi Series Line Chart With Custom ToolTips in JavaScript

In this blog post we will build a line chart with 4 different series and custom labels on both axes. The chart renders tooltips with custom formatting. You can see the chart online here:

I. Initial Setup

We start by creating a blank HTML page and there we initialize the HTML Canvas element that will be needed by the Js Chart library.

<canvas id="chart" style="width: 100%; height: 100%; display: block;"></canvas>

You can initialize the canvas as you want – there are no special requirements as to the size, position, scroll settings or anything else. What is important is that you add an id for that canvas – it will be used by the chart library. At the bottom of the page, right before the closing BODY tag we add a reference to the charting JavaScript files that represent the chart library:

<script type="text/javascript" src="Scripts/MindFusion.Common.js"></script>
<script type="text/javascript" src="Scripts/MindFusion.Charting.js"></script>

We also add a reference to another JavaScript file called LineChartTooltips.js. We haven’t created it yet, but this will be the file that will hold the JavaScript code for our chart.

<script type="text/javascript" src="LineChartTooltips.js"></script>
<strong>II. Initializing the Line Chart</strong>

In the LineChartTooltips JavaScript file we first include a reference to the Intellisense file so we can use code completion.


<pre>/// <reference path="Scripts/jspack-vsdoc.js"></reference>

Then we add mappings to the namespaces that we want to use:

var Controls = Charting.Controls;
var Collections = Charting.Collections;
var DateTimeSeries = Charting.DateTimeSeries;
var Drawing = Charting.Drawing;
var ToolTip = Charting.ToolTip;

Now we create the JavaScript chart object. We need a reference to the HTML canvas element, which we get using its id:

var chartEl = document.getElementById('chart');
chartEl.width = chartEl.offsetParent.clientWidth;
chartEl.height = chartEl.offsetParent.clientHeight;

We use the clientWidth and clientHeight properties of the offsetElement for the chart to give the chart its size.

Next we create the LineChart control and set its title and subtitle.

// create the chart
var lineChart = new Controls.LineChart(chartEl);
lineChart.title = "Women as a percentage in all S&amp;E occupations";
lineChart.subtitle = "1993-2010";

III. Labels

The labels for the X and Y axes are set with two lists:

var xlabels = new Collections.List([
    "1993", "1995", "1997", "1999", "2003", "2006",
    "2008", "2010"]);

var ylabels = new Collections.List([
    "0%", "10%", "20%", "30%", "40%", "50%",
    "60%", "70%"]);

By default the labels at the axes are the intervals. We can replace them with the labels of a given chart series by using the supportedLabels property. This property tells the control at which chart element the labels of the series should be rendered – X or Y axis, tooltip, data labels etc. The members are from the LabelKinds enumeration.

The LineChart control uses series that support X and Y values. The best match is the Series2D class. This class supports one list with labels, which are always drawn at the data points. The easiest thing for us to do is to customize the Series2D and make it accept two lists with labels, which we will show them on both axes. Here is how we create the custom class by inheriting from Series2D

SeriesWithAxisLabels = function (xValues, yValues, xLabels, yLabels) {
    this.yLabels = yLabels;
    Charting.Series2D.apply(this, [xValues, yValues, xLabels]);
};

SeriesWithAxisLabels.prototype = Object.create(Charting.Series2D.prototype);

Our custom class is called SeriesWithAxisLabels. It accepts two lists with labels in the constructor. With one of them we call the constructor of the base class. The other we assign to a new property called yLabels.

Now we need to override the getLabel method and return the right label for the X and Y axis.

SeriesWithAxisLabels.prototype.getLabel = function (index, kind) {
    if ((kind &amp; Charting.LabelKinds.XAxisLabel) != 0 &amp;&amp; this.labels)
        return this.labels.items()[index];

    if ((kind &amp; Charting.LabelKinds.YAxisLabel) != 0 &amp;&amp; this.yLabels)
        return this.yLabels.items()[index];
   
    return "";
};

The getLabel method is responsible for providing the correct label according to the kind of labels that is requested. Here we check if we are asked for a label at the X or Y axis and return the label with the correct index from the xLabels or yLabels arrays. Here is how we create that series, which serves only to provide labels for the axes:

var series0 = new SeriesWithAxisLabels(
    new Collections.List([1, 2, 3, 4, 5, 6, 7, 8]),
    new Collections.List([0, 10, 20, 30, 40, 50, 60, 70]),
    xlabels, ylabels
);
series0.supportedLabels = Charting.LabelKinds.XAxisLabel | Charting.LabelKinds.YAxisLabel;
lineChart.series.add(series0);

Note that the data for the X and Y values of series0 corresponds to the positions on the axes where the labels should be rendered.

IV. Data

The data for the chart is provided by two series. They are also of type Series2D However, we do not want them to render the labels at the data points, which is their default behaviour. We would customize once again the Series2D class and make the labels be used for tooltips and not the data points.

We define a new SeriesWithToolTip class that overrides Series2D

SeriesWithToolTip = function (xValues, yValues, labels) { 
    Charting.Series2D.apply(this, [xValues, yValues, labels]);
};

SeriesWithToolTip.prototype = Object.create(Charting.Series2D.prototype);

The difference is the getLabel method. When asked for a label for the tooltip it returns the label at the given position from the series’ labels list:

SeriesWithToolTip.prototype.getLabel = function (index, kind) {
    if ((kind &amp; Charting.LabelKinds.ToolTip) != 0 &amp;&amp; this.labels)
        return this.labels.items()[index];   

    return Charting.Series2D.prototype.getLabel.apply(this, [index, kind]);
};

We create a data series from the SeriesWithToolTip kind this way:

//first series
var series1 = new SeriesWithToolTip(
    new Collections.List([1, 2, 3, 4, 5, 6, 7, 8]),
    new Collections.List([21.3, 21.5, 21.7, 23, 26.3, 26.1, 26.3, 27.5])
);

series1.title = "All S&amp;E occupations";
var tooltips = new Collections.List();

for (let step = 0; step &lt; series1.yData.count(); step++) {
    tooltips.add(series1.title + " for " + xlabels.items()[step] + ": " +
        series1.yData.items()[step] + "%");
}
series1.labels = tooltips;
series1.supportedLabels = Charting.LabelKinds.ToolTip;
lineChart.series.add(series1);

We generate the tooltip in a list, because we want the text to combine data from the xLabels and its yData list.

V. Styling the Chart

the JavaScript Chart library supports several styles to be applied on the chart depending on what you want to achieve. In our case the best choice is the PerSeriesStyle class, which colours all the elements of a Series with the subsequent brush from its strokes and fills collections.

// create line brushes
var firstBrush = new Drawing.Brush("transparent");
var secondBrush = new Drawing.Brush("#EA3F36");
var thirdBrush = new Drawing.Brush("#1A3D95"); 
var fourthBrush = new Drawing.Brush("#717173");
var fifthBrush = new Drawing.Brush("#407D39");

var style = new Charting.PerSeriesStyle();
style.fills = style.strokes = new Collections.List([firstBrush, secondBrush, thirdBrush, fourthBrush, fifthBrush]);
style.strokeDashStyles = new Collections.List([Drawing.DashStyle.Dash, Drawing.DashStyle.Dash,
Drawing.DashStyle.Dash, Drawing.DashStyle.Dash, Drawing.DashStyle.Dash]);
style.strokeThicknesses = new Collections.List([2, 2, 2, 2, 2]);
lineChart.plot.seriesStyle = style;

The PerSeriesStyle class also provides us with properties to specify the DashStyle and the strokeThickness of the brushes.

The styling of the axes and the fonts is done via the properties of the Theme class. Each chart has a theme property of type Theme. You can use it to customize many properties of the chart:

lineChart.legendTitle = "";
lineChart.gridType = Charting.GridType.Horizontal;
lineChart.theme.axisTitleFontSize = 14;
lineChart.theme.axisLabelsFontSize = 12;
lineChart.theme.subtitleFontStyle = Charting.Drawing.FontStyle.Bold;
lineChart.theme.titleFontStyle = Charting.Drawing.FontStyle.Bold;
lineChart.theme.subtitleFontSize = 16;
lineChart.theme.dataLabelsFontSize = 12;

Note the dataLabelsFontSize property here. It regulates the font not only for the data labels but for the labels of the legend. That is why we set it, though we do not render data labels. There are several dataLabels properties like dataLabelsFontName, which customize different aspects of the labels at chart series and legend.

VI. Legend

You can show the legend with showLegend property, which is true by default. The legendTitle property sets the title of the legend, which we set to an epty string. The labels for each series are taken from the series’ title property:

lineChart.legendTitle = "";

series1.title = "All S&amp;E occupations";
.................
series2.title = "Computer/mathematical scientists";
..................
series3.title = "Engineers";

We can customize the background and border of the legend through properties of the theme or the LegendRenderer:

lineChart.legendRenderer.background = new Drawing.Brush("#f2f2f2");
lineChart.legendRenderer.borderStroke = new Drawing.Brush("#c0c0c0");

VII. ToolTips

The tooltips are automatically rendered when the user hovers over a data point. We make the data points visible by setting showScatter to true:

lineChart.showScatter = true;

Then we set different properties of the TooltTip class to achieve the desired look of the tooltips:

ToolTip.brush = new Drawing.Brush("#fafafa");
ToolTip.pen = new Drawing.Pen("#9caac6");
ToolTip.textBrush = new Drawing.Brush("#717173");
ToolTip.horizontalPadding = 6;
ToolTip.verticalPadding = 4;
ToolTip.horizontalOffset = -6;
ToolTip.verticalOffset = -4;
ToolTip.font = new Charting.Drawing.Font("Arial", 12, Charting.Drawing.FontStyle.Bold);

The ToolTip class is a static class and we can set the properties directly.

At the end, we should always call draw() to see the chart correctly rendered on the screen:

lineChart.draw();

You can download the sample with the JavaScript chart libraries and the Intellisense file from this link:

http://mindfusion.eu/samples/javascript/chart/JsLineChartTooltips.zip

About Charting for JavaScript: MindFusion library for interactive charts and gauges. It supports all common chart types including 3D bar charts. Charts can have a grid, a legend, unlimitd number of axes and series. Scroll, zoom and pan are supported out of the box. You can easily create your own chart series by implementing the Series interface.
The gauges library is part of Charting for JavaScript. It supports oval and linear gauge with several types of labels and ticks. Various samples show you how the implement the gauges to create and customize all popular gauge types: car dashboard, clock, thermometer, compass etc. Learn more about Charting and Gauges for JavaScript at https://mindfusion.eu/javascript-chart.html.

Using MindFusion JavaScript Components With WordPress Elementor Plugin

In this blog post we will describe the steps that are necessary to follow if you want to use MindFusion JavaScript library with WordPress Elementor plugin.

This guide assumes you are familiar with Elementor. For clarity we will show you how to show the JavaScript Scheduler from the “First Schedule” sample. The steps can be repeated for any MindFusion JavaScript library.

I. Add HTML Tag

The Js Scheduler requires an element to be associated with. We create an HTML Elementor widget in the place of the web page where we want the schedule to appear. Then we write in it the HTML code that creates the calendar div:

Elementor HTML Widget

Use the <HTML> widget of Elementor to insert code for the <div> element required by MindFusion JS Scheduler

II. Copy the JavaScript and CSS Files

The First Schedule sample requires reference to two JavaScript files and a CSS file with the calendar theme.

We copy the theme we will use in a new folder called “calendar-themes” into the directory of your WordPress website. This folder should be located in the subfolder that has the name of the WordPress theme you are using. This subfolder is located in the wp/content/themes/ directory. The path should be:

http://www.yoursite.any/wp-content/themes/your-theme/calendar-themes/first-theme.css

Instead of “calendar-themes” you can use any other name for your folder.

Next, copy the MindFusion.Scheduling.js and FirstSchedule.js files in a new folder called “js”, which is located at the same place where the calendar-themes folder is placed. The path should be:

http://www.yoursite.any/wp-content/themes/your-theme/js/FirstSchedule.js

http://www.yoursite.any/wp-content/themes/your-theme/js/MindFusion.Scheduling.js
WordPress directory structure

The directory structure of a WordPress blog with the newly created “js” and “calendar-themes” folders.

III. Get a Header/Footer WordPress Plugin.

Here is a list of the available options:

https://www.cminds.com/best-5-wordpress-header-footer-management-plugins/

For the purpose of this tutorial we installed “Insert Headers and Footers” but any other plugin will do. After you install the chosen plugin add the reference to the scheduler themes and the JavaScript files according to the instructions of the plugin provider. In our case we did this from the WordPress Dashboard > Settings > Insert Headers and Footers menu.

There we placed in the “Scripts in Header” text box:

 	<link href="http://ubydesign.net/wp-content/themes/twentyseventeen/calendar-themes/first-theme.css" rel="stylesheet">

And in the “Scripts in Footer” textbox:

<script src="http://ubydesign.net/wp-content/themes/twentyseventeen/js/MindFusion.Scheduling.js" type="text/javascript"></script>
<script src="http://ubydesign.net/wp-content/themes/twentyseventeen/js/FirstSchedule.js" type="text/javascript"></script>

On our test blog we use the twentyseventeen theme. That’s how the Header/Footer settings look like:

Header/Footer settings

The header references the CSS theme of the calendar, the footer adds references to the required JavaScript files.

You can check the live page on: http://ubydesign.net/blog/js-calendar-elementor/

Learn more about MindFusion JavaScript components at: https://mindfusion.eu/products.html#javascript

For technical questions please use the MindFusion discussion board: https://mindfusion.eu/Forum/YaBB.pl

Custom Diagram Nodes With Clipped Images

In this blog post we will create an org chart diagram that uses custom nodes for each employee. The diagram will be created with the Diagramming for JavaScript library. For the nodes we use the CompositeNode class, which enables us to create diagram nodes whose appearance can be defined via composition of components and layout containers.

Click on the image below to run the sample:

Custom Composite Nodes with Clipped Images

I. References and HTML Settings

The first thing that we’ll do is create a web page for the sample and add the references to the necessary JavaScript files. In the section of the page we provide a reference to the following jQuery files:

<a href="http://common/jquery.min.js">http://common/jquery.min.js</a>
<a href="http://common/jquery-ui.min.js">http://common/jquery-ui.min.js</a>

At the end of the HTML page, just before the closing tag we place references to the two JavaScript files used by the Diagramming library:

<a href="http://MindFusion.Common.js">http://MindFusion.Common.js</a>
<a href="http://MindFusion.Diagramming.js">http://MindFusion.Diagramming.js</a>

Our sample has its JS code in a separate file called Script.js. We place a reference to it as well:

<a href="http://Script.js">http://Script.js</a>

The diagram library needs an HTML Canvas to draw itself onto. We add one in the middle of the web page:

<div style="width: 100%; height: 100%; overflow: auto;">
	<canvas id="diagram" width="2100" height="2100">
		This page requires a browser that supports HTML 5 Canvas element.
	</canvas>
</div>

II. The OrgChartNode

In the Script.js file we first add mappings to some enums and classes that we’ll use from the diagram library:

var Diagram = MindFusion.Diagramming.Diagram;
var CompositeNode = MindFusion.Diagramming.CompositeNode;
var Behavior = MindFusion.Diagramming.Behavior;

var Alignment = MindFusion.Drawing.Alignment;
var Rect = MindFusion.Drawing.Rect;

Now we call the classFromTemplate method of CompositeNode that generates a node class using a JSON template that we’ll provide:

var OrgChartNode = CompositeNode.classFromTemplate("OrgChartNode",
{
component: "GridPanel",
rowDefinitions: ["*"],
columnDefinitions: ["22", "*"],
...............

In this code we indicate the panel that will be used by the CompositeNode is a GridPanel. Then we declare two lists that set the width and height of the grid rows and columns. The number of members in each array indicate how many rows/columns the grid has. In our case we have one row that takes all place and two columns: one is with fixed with of 22 pixels, the other takes the rest of the available space.

The JSON definition of the CompositeNode continues with an array with the children:

children:
[
{
component: "Rect",
name: "Background",
pen: "black",
brush: "white",
columnSpan: 2
},
{
component: "Image",
name: "Image",
autoProperty: true,
location: "ceo.png",
margin: "1",
imageAlign: "Fit"
},

The first child uses a Rect component that we call “Background”. It is rendered with a white brush, has a black outline and spans on two columns e.g. it fills all available space or each node.

The second child is an image. Note the row:

autoProperty: true

That means that we want to be able to access this component as a property. In such cases the library generates automatic set/get methods using the name of the component. In our sample they will be setImage / getImage.

The third child is a StackPanel component. This is the container for the text labels next to the node. This child has its own collection of children nodes:

component: "StackPanel",
orientation: "Vertical",
gridColumn: 1,
margin: "1",
verticalAlignment: "Near",
children:
[
{
component: "Text",
name: "Title",
autoProperty: true,
text: "title",
font: "Arial bold"
},
{
component: "Text",
name: "FullName",
autoProperty: true,
text: "full name",
pen: "blue",
padding: "1,0,1,0"
},
{
component: "Text",
name: "Details",
autoProperty: true,
text: "details",
font: "Arial 3"
}

The children of this new StackPanel are text components, which are called Title, FullName and Details. They have their autoProperty set to true, which means we can access their value through automatic setter and getter methods.

III. The Diagram and the Nodes

in the read() function of the document we create an instance of the Diagram class using a reference to the canvas we’ve created in section I.

// create a Diagram component that wraps the "diagram" canvas
diagram = Diagram.create($("#diagram")[0]);

Then we enable interactive drawing of custom nodes by calling setCustomNodeType and Then we enable interactive drawing of custom nodes by calling setCustomNodeType and setBehavior:

// enable drawing of custom nodes interactively
diagram.setCustomNodeType(OrgChartNode);
diagram.setBehavior(Behavior.Custom);

The behavior o the diagram is set to Custom, which means that when the user starts drawing nodes the library shall draw nodes specified by CustomNodeType. The setCustomNodeType method tells the diagram that these custom nodes are of type OrgChartNode.

Now it is really easy and intuitive to create nodes:

var node1 = new OrgChartNode(diagram);
node1.setBounds(new Rect(25, 15, 60, 25));
node1.setTitle("CEO");
node1.setFullName("John Smith");
node1.setDetails(
"Our beloved leader. \r\n" +
"The CEO of this great corporation.");
node1.setImage("ceo.png");
diagram.addItem(node1);

We create a few more nodes using the same code and we bind them in a hierarchy. The links among the nodes are created by calling the Diagram Factory createDiagramLink method of the diagram Factory class:

diagram.getFactory().createDiagramLink(node1, node2);
diagram.getFactory().createDiagramLink(node1, node3);
diagram.getFactory().createDiagramLink(node1, node4);
diagram.getFactory().createDiagramLink(node4, node5);

IV. Rounded Images

We want to add now a custom feature to the node – instead of drawing the image as a rectangle we want to clip it and show it as an ellipse. We’ll do this by using a method that replaces the standard setImage method.

The new method is called createImageClip and takes as parameters two objects: one is the image URL and the other is the node that uses this image.

function createImageClip(path, node)
{
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
img = document.createElement('img');
..............

We create two HTMLElements – canvas and image, and we get the 2D context of the Canvas. Then, in an event handler of the onload event of the image we clip the canvas to an area defined by a Path. The path reads the size of the image and creates a full arc e.g. a circle inside that rectangle. Then the context draws the image and the new canvas is set as an image to the node using the setImage method:

img.src = path;
img.onload = function ()
{
canvas.width = img.width;
canvas.height = img.height;
var halfSize = img.width / 2;
ctx.save();
ctx.beginPath();
ctx.arc(halfSize, halfSize, halfSize, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();

ctx.drawImage(img, 0, 0, img.width, img.height);

node.setImage(canvas.toDataURL());
};

You can use this approach to create clippings of images with variable shape.

Now instead of calling:

node1.setImage("ceo.png");

we call our custom method this way:

createImageClip("ceo.png", node1);

We do this for all nodes in the org chart.

That’s the end of this tutorial. You can download the sample together with all JavaScript libraries used from this link:

Custom Nodes With Image Clipping in JavaScript: Sample Download

Find out more about Diagramming for JavaScript at https://mindfusion.eu/javascript-diagram.html

Binding the Java Planner to Microsoft SQL Server Using JDBC

In this blog post we will bind to an MS SQL database called bookings. There we will select all data from a table named booking_data. The data is DateTime values. We will use the values to change the background of corresponding calendar cells in a simple Java application. The Java application renders a single-month calendar built with MindFusion Scheduler for Java library.

I. MS SQL EXPRESS Server Configuration

We download and install MS SQL EXPRESS server from https://www.microsoft.com/en-us/sql-server/sql-server-downloads. The installation also includes an application called “Sql Server Configuration Manager”. We start that application and click on the “SQL Services” tab. There we need to make sure that two services are running:

  • SQL Server
  • SQL Server Browser

You start these services by pressing the arrows in the toolbar at the top. If you cannot do this you need to change the Start Mode for this service. Double click it and in the Properties dialog that appears click on the “Service” tab. There you will find the “Start Mode” property and change it to “Manual”. Once you’ve done this you can start, stop or pause the service from the toolbar icons.

SQL Server Config Manager: Services

In order to start an SQL Server Service you might have to change its Start Mode to “Manual”.

Then we click on the “SQL Native Client” node and we select the “Client Protocols” tab. We make sure the TCP/IP Protocol is enabled.

SQL Server Config Manager: Enable TCP/IP

Make sure the TCP/IP protocol is enabled for the JDBC connection to succeed

The next step is to download Microsoft SQL Server Management Studio from https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-2017

Once we install it and start it we can create a new database called bookings. We right click on the Databases menu and choose “New Database”. We call it “bookings”. Then we expand the tree under “bookings” and right click on the “Tables” node. A window opens where we can define the columns for our new table. We add two columns:

  • id of type integer, which we set at primary key by right-clicking on it.
  • booked_date of type DateTime which will hold the dates that are booked.
Create a new table using MS SQL Server Management Studio

MS SQL Server management Studio: the dialog for defining a new table

After we are done we choose save and at this point we can provide a name for our table. We call it booking_data. With the table defined we right-click on it and choose “Edit Top 200 Rows”. There we add just three days (Jan 16th, Jan 22nd, Jan 26th) all of which in the current month. The data is auto-saved.

MS SQL Server management Studio: Table Edit

MS SQL Server Management Studio: here is how you edit the table data

The next step is to create a new user that will connect to this database. We click the “Security” node on the navigation tree and then “Logins”. Right-click and we choose “New Login”. In the dialog that opens we provide username and password. In order to do that we need to have the Login method set to “SQL Server authentication”. In the next tab “Server Roles” the new user must have “public” role. Then in “User Mapping” we tick the “bookings” database. In the Securables tab in the “Grant” grant column for the user we tick the “Connect SQL” permission. Then we close the dialog.

Grant SQL Connect to a DB User

Grant the new user the right to perform an SQL connection.

We get back to the bookings database and right-click on it. We choose “Properties” and from the dialog we click on the “Permissions” menu. There we select the user we’ve just created and in the Grant column of the underlying table we grant her the “Select” permission.

Granting User Permissions

Grant the DB user ‘Select’ permission to perform the required SQL query

With that the setup of our server and user is ready.

II. JDBC Driver & MS SQL Express Connection Properties

We download Microsoft’s JDBC Driver for MS SQL Server from this link: https://docs.microsoft.com/en-us/sql/connect/jdbc/microsoft-jdbc-driver-for-sql-server?view=sql-server-2017 and extract it. Next we create a new Java project. For this project we’ve used IntelliJ IDEA but any other Java IDE will do. In the project tree to the right we create a subfolder that we call “libs”. There we copy the jar of JDBC driver from the folder where we extracted it. Microsoft provides two versions of the driver depending on the JRE that you use. In our case we choose the version for JRE 10, which is called mssql-jdbc-7.0.0.jre10.jar. Next we right-click on the name of our project and select “Open Module Properties”. In the dialog we choose the “Modules” menu and there we click on the “Dependencies” tab and select the mssql-jdbc-7.0.0.jre10.jar module.

Configuring IntelliJ Project Modules

Configuring the IntelliJ Project to include the JDBC driver module

We click on the src folder of the project and add a new class, which we call MainWindow.java. In it we write the method establishConnection. This method is responsible for connecting to the MS SQL database “bookings”. Here is the code that makes the connection:

private void establishConnection() throws ClassNotFoundException
{

Connection conn = null;
PreparedStatement pst;

try {
// db parameters
String sql = "SELECT booked_date FROM booking_data";

String userName = "mindfusion";
String password = "mf123";

String url = "jdbc:sqlserver://DESKTOP-NV9S0TU\\SQLEXPRESS;databaseName=bookings;";

Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
conn = DriverManager.getConnection(url, userName, password);

pst = conn.prepareStatement(sql);
ResultSet rs = pst.executeQuery();

If you’ve followed strictly the steps we’ve outlined so far at this point you would successfully connect to your MS SQL Server with the credentials you’ve set up following the guide so far.

III. The Schedule Application

We download MindFusion Java Swing Scheduler from https://mindfusion.eu/java-scheduler.html and unzip it. We copy JPlanner.jar in the libs folder of the project and add it as a project dependency from the “Open Module Settings” menu. Then we define a Calendar variable and assign it to a new instance of the Calendar class.

public MainWindow() throws ClassNotFoundException
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(368, 362);
setTitle("MindFusion.Scheduling Sample: Minimal Application");

calendar = new Calendar();
calendar.setTheme(ThemeType.Light);
..................
..................
..................

establishConnection();
}

private Calendar calendar;

At the end of the method we call establishConnection and connect to the MS SQL Server.

IV. Styling the Calendar Dates

The aim of our sample application shall be to color those cells of the calendar that correspond to the dates we’ve read from the database. In order to do this we use the DateStyle class that sets some useful appearance properties to a range of cells that are specified with the setFrom and setTo methods. We use setBrush to change the background of the cell.

while (rs.next()) {
System.out.println(rs.getString("booked_date"));
Date date = rs.getDate("booked_date");

DateStyle dStyle = new DateStyle();
dStyle.setFrom(new DateTime(date));
dStyle.setTo(new DateTime(date));
Style style = new Style();
style.setBrush(new SolidBrush(Color.pink));
dStyle.setStyle(style);

calendar.getDayStyles().add(dStyle);

}

Finally we add the style to the DayStyles collection of the calendar.

Here is the final application:

Scheduling application in Java Swing with MS SQL Server JDBC Connection

MindFusion Java Swing application with the Scheduling library and MS SQL Server

You can download the project together with the MS SQL Server JDBC driver library and the scheduling library from this link:

Download JPlanner Sample Application That Uses MS SQL Server JDBC Connection

About MindFusion Scheduling for Java Swing: The library provides extensive feature-set for creating and customizing all sorts of calendars, task lists, time-management tables, resource allocation tables and other. It boasts various options for customizing appearance and numerous events for handling user actions. The distribution archive includes a lot of samples and extensive documentation. Learn more at https://mindfusion.eu/java-scheduler.html

Interactive Event Timetable in JavaScript

This blog post describes the main steps on how to create a schedule table, which shows the allocation of college rooms to different courses. Users can filter the courses by lecturer(s).

I. Initial Setup

We start by copying the JavaScript scheduler files that we’ll use in the directory of our project. These are:

  • MindFusion.Scheduling.js – represents the Js Scheduler library
  • MindFusion.Scheduling-vsdoc.js – provides Intellisense support
    standard.css – in a subdirectory “themes”, this is the CSS theme styling of the resource table
  • planner_lic.txt – paste your license key here to disable the trial version label.

We create then 2 more files specifically for our application:

  • ResourceView.html – the web page of the application
  • ResourceView.js – the JavaScript code that implements the dynamic features of our application.

II. The HTML Page

In the head section of our web page we first create a reference to the theme file:

 	 	<link rel="stylesheet" type="text/css" href="themes/standard.css">

At the end of the web page, just before the closing </body> tag we add a reference to the Scheduling.js file that contains the scheduling features and the ResourceView.js files that we’ll write for the application:

<script src="MindFusion.Scheduling.js" type="text/javascript"></script>
<script src="ResourceView.js" type="text/javascript"></script>

The calendar library requires an HTML <div> element, which is used to render it. We add one:

<div id="calendar" style="height: 100%; width: 100%;"></div>

It is important that you add an id to this <div> because we need to reference it in the JS code behind file.

III. Basic JavaScript Settings

At the top of the JavaScript code-behind file we add a reference to the Intellisense file. We also create a mapping to MindFusion.Scheduling namespace:

/// <reference path="MindFusion.Scheduling-vsdoc.js"></reference>
var p = MindFusion.Scheduling

Then we create the calendar object. We need a reference to the <div> element that will render it:

// create a new instance of the calendar
calendar = new p.Calendar(document.getElementById("calendar"));

For this sample we will use the ResourceView The currentView property specifies that. In addition, we set the count of visible cells in the calendar to 7. That is done through the resourceViewSettings property of the calendar

// set the view to ResourceView, which displays the distribution of resources over a period of time
calendar.currentView = p.CalendarView.ResourceView;

// set the number of visible cells to 7
calendar.resourceViewSettings.visibleCells = 7;

The itemSettings proeprty lets us customize the items in the schedule We use titleFormat and tooltipFormat to specify how the title and tooltip of each item will be rendered. Both properties use special format strings:

  • %s – the start date will be rendered
  • %e – the end date of the item will be rendered
  • %d – the details of the item will be rendered.

You can specify the way dates and time are formatted by adding the desired format in brackets:

// show hours on items
calendar.itemSettings.titleFormat = "%s[HH:mm] - %e[HH:mm] %h";
calendar.itemSettings.tooltipFormat = "%d";

Then we set the theme of the calendar to standard, whose css file we referenced in the web page:

calendar.theme = "standard";

and we make one more adjustment – the name of contacts will be taken from the last name of the person. Possible valies are “F”, “M” and “L” – for first, middle and last name.

calendar.contactNameFormat = "L";

IV. Resources

When the calendar initially loads there are several contacts and locations available. The objects that represent them are instances of the Contact and Location classes. After we create them we add them to the contacts and locations collections of the calendar schedule.

var resource;

// Add professor names to the schedule.contacts collection.
resource = new p.Contact();
resource.firstName = "Prof. William";
resource.lastName = "Dyer";
calendar.schedule.contacts.add(resource);

resource = new p.Location();
resource.name = "Room D";
calendar.schedule.locations.add(resource);

Now, when the user creates a new course they will see the Contact and Location in the Options pane of the “Create Item” form:

V. Items

The items are instances of the Item class. They represent the classes of the different lecturers. We use the startTime and endTime properties of Item to specify when the class takes place. The subject property gives the name of the class:

//always start with the current date
var date = p.DateTime.today();

item = new p.Item();
item.startTime = p.DateTime.addHours(date.addDays(1), 14);
item.endTime = p.DateTime.addHours(item.startTime, 1);
item.subject = "Classical Mechanics";

We use the location and contacts properties to set where the lecture takes place and who teaches it. Note that the contacts property is of type collection and we can assign several lecturers to one class:

item.location = calendar.schedule.locations.items()[0];
item.contacts.add(calendar.schedule.contacts.items()[0]);

We get the location and the contact from the schedule’s lists with locations and contacts We must also set the details of the item – they will be rendered as a tooltip, if you remember. We want the tooltip to show the two names of the lecturer and the location. Here is how we must define it:

item.details = item.contacts.items()[0].firstName + " " +
item.contacts.items()[0].lastName + " - " + item.location.name;

We must add the item to the items collection of the schedule we render the calendar render the calendar

calendar.render();

VI. Events

When users create new items we must set their details to tell the name and the location of the new class. We handle the itemCreating event to do this:

// attach handler - creating an item
calendar.itemCreating.addEventListener(handleItemCreating); 

function handleItemCreating(sender, args) {
    handleItemModified(sender, args);
    if (args.item.contacts.count() &gt; 0) {
        //the details field is used by the tooltip
        args.item.details = args.item.contacts.items()[0].firstName + " " +
                args.item.contacts.items()[0].lastName;

        if (args.item.location != null)
            args.item.details += " - " + args.item.location.name;
    }

}

The itemCreating event provides an instance of the ItemModifyingEventArgs class as a second argument to the handler method. There we use the item property that tells us which item is being modified. We then take the desired contact and Location information from the contacts and location properties of the item.

When a new course item is dragged to another location we must change its color accordingly. We do this by handling the itemModified event.

// attach handler - modifying an item
calendar.itemModified.addEventListener(handleItemModified);

The diferent background color of the items is achieved by custom CSS classes. We use the cssClass property of the Item class. The CSS styles are defined in the <HEAD> section of the web page:

 .mfp-planner.standard .itemClass1 .mfp-item {
            background-color: 	#0c71af;
        }

.mfp-planner.standard .itemClass2 .mfp-item {
            background-color: #f81e1e;
        }
...........

The handler method checks the new location and assigns the appropriate CSS style:

function handleItemModified(sender, args)
{
    // you don't have to check any other conditions like dragging to another room, 
    // as it will stay the same color if you make other changes (other than dragging to a different room)
    if (args.item != null){
        switch (args.item.location.name) {
            case "Room A":  //we can also implement it with for
                args.item.cssClass = 'itemClass1';
                console.log("a");
                break;
            case "Room B":
                args.item.cssClass = 'itemClass2';
                break;
            case "Room C":
                args.item.cssClass = 'itemClass3';
                break;
            case "Room D":
                args.item.cssClass = 'itemClass1';
                break;
            case "Room E":
                args.item.cssClass = 'itemClass2';
                break;
            case "Room F":
                args.item.cssClass = 'itemClass3';
                break;
            default:
                args.item.cssClass = 'itemClass1';
        }
    }
}

The item property of the args parameter of the handler method provides access to the item that was modified.

VII. Filtering Professors

We want to add one last feature to our application. We want the user to be able to render courses only by a given professor.

We first add checkboxes with the names of the lecturers. Each checkbox has the same handler method for the click event:

<input id="dyer" checked="checked" name="subscribe" type="checkbox" value="Dyer>
<label for=">Prof. William Dyer

<input id="fletcher" checked="checked" name="subscribe" type="checkbox" value="Fletcher">
<label for="fletcher">Prof. Ann Fletcher</label>
...........................

The handler method needs to look at two cases. The first case is when the class is taught by a single professor. In this case we cycle through all items and make the item visible or not depending on whether the check box with the name of the professor is checked:

// if there is at least one present professor from the lecture professors, the lecture will not disappear
function handleClick(cb) {
for (var i = 0; i &lt; calendar.schedule.items.count(); i++) {
        var item = calendar.schedule.items.items()[i]; //we iterate through every element
        if (item.contacts.count() == 1) {
            if (item.contacts.items()[0].lastName == cb.value)
                item.visible = cb.checked;
        }
      }
.......................
}

In the second case we look at courses that are taught by more than one lecturer. In this case we show the item if the checkbox with the name of at least one of the lecturers is selected:

else if (item.contacts.count() &gt; 1) {
for (var j = 0; j &lt; item.contacts.count() ; j++) {
                if (item.contacts.items()[j].lastName == cb.value) { // the checked/unchecked professor is in the contacts of this item
                    if (cb.checked == true) item.visible = true; // if there is a check, the item must be visible
                    else { // if there is no check, we see if there is at least one professor in the list of contacts of the item
                        item.visible = professorPresent(item);
                    }

                }
            }
        }

Finally we repaint the calendar:

// repaint the calendar
this.calendar.repaint(true);

Here the professorPresent method checks if at least one of the check boxes with professors that are present as lecturers in the item that we provide as argument are selected:

// return true if even 1 professor from the item's contacts is present, false otherwise
function professorPresent(item) {
    console.log(item.contacts.count());
    for (var j = 0; j &lt; item.contacts.count() ; j++) {
        var checkBoxId = item.contacts.items()[j].lastName.toLowerCase();
        var checkBox = document.getElementById(checkBoxId);
        if (checkBox!= null &amp;&amp; checkBox.checked == true) {
            return true;
        }
    }
    return false;
}

And that’s the end of this blog post. Here is a link to download the complete source code of this application:

Download The Sample Resource View Application

About MindFusion JavaScript Scheduler: MindFusion Js Scheduler is the complete solution for all applications that need to render interactive timetables, event schedules or appointment calendars. Fully responsive, highly customizable and easy to integrate, you can quickly program the JavaScript scheduling library according to your needs. Find out more at https://mindfusion.eu/javascript-scheduler.html

Negative Bar Stack in WinForms

Thia post will demonstrate how to create a horizontal stacked bar chart with negative values. We will use the Charting for WinForms component and the final chart looks like this:

Negative Stacked Bar Chart in WinForms with the Chart Control

Negative Stacked Bar Chart in WinForms with the Chart Control

I. Data

The chart will use four series. The first two series are the ones that you clearly see – the red and blue one. We initialize two data arrays with random values that represent the data:

var firstBarX = new List<double>(11);
var secondBarX = new List<double>(11);

Random r = new Random();
            
for(int i = 0; i < 11; i++)
   {
       firstBarX.Add(2.2 + r.NextDouble());
       secondBarX.Add(2.4 + r.NextDouble());
    }

We need a list with data values that are exactly the same as the first series, but are negative. They will provide a transparent initial series, whose bars will offset the first, red, series as much as the value of the red bar should be:

//generate data for the transparent series
var transparentBarX = new List<double>(firstBarX.Count);

for (var i = 0; i < firstBarX.Count; i++)			
    transparentBarX.Add(0 - firstBarX[i]);

The data for the Y-axis is very simple. We just need a list with the numbers from 1 to 12:

//data for the Y-axis
var barY = new List<double>();
for (int i = 1; i < 12; i++)			
	barY.Add(i);

II. Labels
We will create two lists with the labels that we will show – for the two axis. The labels for the Y-axis will be used as tooltips as well. We just initialize two string lists:

//initialize labels for the X axis
var ageLabels = new List<string>() { "0-5", "6-11", "12-17", "18-23", "24-29", "30-35",
		   "36-41", "42-47", "48-53", "54-59", "60-65" };

//initialize labels for the Y axis.
var percentageLabels = new List<string> { "5%", "4%", "3%", "2%", "1%", "0%", 				"1%", "2%", "3%", "4%", "5%", };

We will use this label lists in the next section, when we create the series.

III. Series

We will use 4 series, of type Series2D. This series is useful for its SupportedLabels property – it allows us to specify what the labels of the series would be used for. We start with the transparent series. Its labels will be used for custom labels at the Y-axis:

var seriesTransparent = new MindFusion.Charting.Series2D(transparentBarX, barY, ageLabels);
seriesTransparent.SupportedLabels = MindFusion.Charting.LabelKinds.YAxisLabel;
seriesTransparent.Title = "";

We use for X-data the negative values you remember from the previous paragraph. The age labels are those that provide the data for the axis.

Then we initialize the two series for the chart data:

var seriesFirst = new MindFusion.Charting.Series2D(firstBarX, barY, ageLabels);
seriesFirst.SupportedLabels = MindFusion.Charting.LabelKinds.ToolTip;
seriesFirst.Title = "Female";

var seriesSecond = new MindFusion.Charting.Series2D(secondBarX, barY, ageLabels);
seriesSecond.SupportedLabels = MindFusion.Charting.LabelKinds.ToolTip;
seriesSecond.Title = "Male";

The last series that we create is just to provide data for the X-axis and we set its SupportedLabels property to MindFusion.Charting.LabelKinds.XAxisLabel. The X-data for this series corresponds to the coordinates of the X-labels, that’s why set the numbers from -5 to 5 as X-data:

var firstParamList = new List<double>();
      for (int i = -5; i < 6; i++)			
	 firstParamList.Add(i);

The Y-data could be all zeros, we won’t use them anyway.

var secondParamList = new List<double>();
    for (int i = 0; i < 12; i++)			
	secondParamList.Add(0);

And we create the series this way:

//the purpose of this series is to only supply the Xaxis labels, it is transparent.	
var seriesThird = new MindFusion.Charting.Series2D(firstParamList, secondParamList, percentageLabels);           	
seriesThird.SupportedLabels = MindFusion.Charting.LabelKinds.XAxisLabel;
seriesThird.Title = "";

After you have created all series, you should add them to the Series collection of the BarChart:

barChart.Series = new ObservableCollection<Series>
	{ seriesTransparent, seriesFirst, seriesSecond, seriesThird };
           	

IV. Axes and Grid

We need to fix the divisions of the X-axis if we want to show a grid and the grid to be neatly aligned with the axes. We will set the min value to be -6, the interval 1 and the max value to be 6:

barChart.XAxis.Interval = 1;
barChart.XAxis.MinValue = -6;
barChart.XAxis.MaxValue = 6;		

We will use three more properties to hide the interval labels at both axes, show ticks on them and set a title for each axis:

barChart.XAxis.Title = "Percentage of the Population";
barChart.YAxis.Title = "Ages";
			
barChart.ShowYCoordinates = false;
barChart.ShowXCoordinates = false;

barChart.ShowXTicks = true;
barChart.ShowYTicks = true;

Finally, we have to set the grid and specify that the bars are horizontal:

barChart.GridType = GridType.Vertical;
barChart.HorizontalBars = true;

V. Styling

Styling the chart is done though the SeriesSyle property of the Plot. You can assign to it different series types, you can check the list at the ISeriesStyle interface page in the documentation:

barChart.Plot.SeriesStyle = new PerSeriesStyle()
{
	Strokes = new List<MindFusion.Drawing.Brush> {
		firstBrush, new SolidBrush(Color.FromArgb(179, 0, 0)), 
                new SolidBrush(Color.FromArgb(0, 0, 102)), firstBrush
		},
		StrokeThicknesses = new List<double> {
			 0,2,2,0
		},
		Fills = new List<MindFusion.Drawing.Brush>()
		{
			firstBrush, secondBrush, thirdBrush, firstBrush
	}
};

This style indicates that each brush from its collection will be used for one series in the chart. We assign to it 4 brushes and 4 strokes. The first brush is transparent, the second one is red, the other is blue and the last one is black – we won’t draw with it anyway.

The Theme property of the chart holds a lot of options for customizing the appearance. Here are just a few of them:

barChart.Theme.LegendBorderStrokeThickness = 1;
barChart.Theme.LegendBorderStroke = new SolidBrush(Color.Black);
barChart.Theme.GridColor2 = Color.White;
barChart.Theme.GridColor1 = Color.FromArgb(250, 250, 250);
barChart.Theme.GridLineColor = Color.FromArgb(153, 153, 153);
barChart.Theme.PlotBackground = new SolidBrush(Color.FloralWhite);
...........
..........

And that’s the end of this step-by-step guide. You can download the sample together will all necessary libraries from this link:

Download Negative Stack Bar Chart in CS Sample

About MindFusion Charting for WinForms: A versatile dashboard component that provides your WinForms application with the ability to create fascinating charts, interactive dashboards and practical gauges. The component combines a flexible API that allows custom combination of chart components to build any type of chart you want. You can add as many axes of any type you want, combine various chart series into a single chart with different data providers each. The control also supports pan and zoom, scroll, unlimited number of legends, grid and a dashboard panel. Linear and oval gauges complete the tool set and guarantee every feature you might need to build the perfect gauge, chart of any type or dashboard in WinForms is right at your fingertips. Learn more at https://mindfusion.eu/winforms-chart.html

A JavaScript Keyboard With Special Language Symbols That Appears When The User Starts Typing

This blog post will demonstrate how to create a keyboard that renders only when the user starts typing in a text box. When the user clicks outside the text box, the virtual keyboard disappears. There is another extra – a selection of languages to the right. When a language is selected, the keyboard renders only the special symbols from the selected language.

You can test the JS Hidden Keyboard sample online from this link.

The application uses MindFusion Virtual Keyboard for JavaScript. Here is a screenshot of the application:

Invisible keyboard in JavaScript

Virtual keyboard in JavaScript that renders only when the user starts typing. The keyboard renders special symbols for several languages.

I. The Keyboards for Spanish, German and French

The three keyboard layouts with special symbols for the three languages are created with the Virtual Keyboard Layout Creator tool, that is packed with the JavaScript Keyboard library. We create a new compact keyboard and delete most of the keys. We type the desired key as character for the rest and use the Properties tab to set the size of the keyboard, as well the layout and the key alignment. Finally, we export the new keyboard layout as a json file (File → Export JavaScript. It is a good idea to save the keyboard layout as xml as well (File → Save As). This way you can load the keyboard gain, when you need to create another layout based on it or correct this one.

We have created now three json files:

  • french-symbols.js
  • german-symbols.js
  • spanish-symbols.js

Let’s look at the contents of one of the json files:

var layoutDef =
{
	width: 565,
	height: 115,
	keys:
[	{	
		code: 162,
		type: "regular",
		content: "ù",
		left: 9,
		top: 10,
		width: 40,
		height: 40
	},
	{	
		code: 162,
		type: "regular",
		content: "û",
		left: 56,
		top: 10,
		width: 40,
		height: 40
	},
………
{	
		code: 162,
		type: "regular",
		content: "œ",
		left: 507,
		top: 58,
		width: 40,
		height: 40
	}
]
};

Each file contains an array named “numpadDef”. We need to change the name, because we will load each list when a certain language is selected, which means we must be able to differentiate among the languages. We rename the lists to layoutDefFr, layoutDefDe and layoutDefEs.

Here is what the Virtual Keyboard Layout Creator Tool looks like:

Keyboard layout creator tool

The virtual keyboard layout creator tool that is part of the JavaScript Keyboard library by MindFusion

II. The HTML Web Page

We create a simple web page, where we add a reference to the JavaScript file of the Virtual Keyboard library:


<a href="http://Keyboard.js">http://Keyboard.js</a>

Note that we place this reference at the end of the file, after the closing tag. The we need reference to the JavaScript files with the definitions of the virtual keyboards that we created in step I.


<script src="french-symbols.js" type="text/javascript"></script>
<script src="spanish-symbols.js" type="text/javascript"></script>
<script src="german-symbols.js" type="text/javascript"></script>

Finally, we add a reference to a JavaScript file that will hold the code for our sample. It will be empty for now.


<script src="HiddenKeyboard.js" type="text/javascript"></script>

The next step is to load the CSS file with the styling for the JS keyboard. We have chosen the Silver theme, you can choose whichever theme you want or create a custom one.


<link href="css/VirtualKeyboard.Silver.css" rel="Stylesheet" />

We have added also a reference to a a stylesheet that aligns correctly the

elements with the keyboard, the text area and the select list.


<link href="style.css" rel="Stylesheet">

It contains code purely to align correctly the elements and we will not examine its contents.

Now, let’s create the text area:


<form id="f1">
<textarea id="text" rows="15" cols="55"></textarea>
…….
</form>

We create a form, called f1 and there we create the HTML textarea element. It handles to events: onfocus and onblur.

Next, the form contains a select with the three languages, whose keyboards with special symbols we have prepared:


<select id="selectedLang" size="3">
<option value="Fr">French</option>
<option value="De">German</option>
<option value="Es">Spanish</option>

</select>

Outside the form, we place a dive with the keyboard:


<div id="keyboard" style="width: 565px;height: 115px" />

The virtual keyboard will be rendered with fixed size and by default is not rendered e.g. it’s display is set to “none”.

III. The JavaScript Code-Behind File

First, we add two namespace mappings:


var VirtualKeyboard = MindFusion.VirtualKeyboard;
var KeyboardLayout = MindFusion.KeyboardLayout;

Then we handle the DOMContentLoaded event to create the Virtual Keyboard object. We use the div element that represents the keyboard as a parameter to the VirtualKeyboard constructor. We have provided the div element with an id in the HTML page.

We also set the selected index of the elements in the language list to -1 e.g. by default no language is selected and the keyboard will show the standard English typing keyboard.


document.addEventListener("DOMContentLoaded", function (event)
{
	document.getElementById("selectedLang").selectedIndex = -1;
	
	var vk = VirtualKeyboard.create(
		document.getElementById("keyboard"));
	vk.setScaleToFitParent(false);	

…………………

});

Then we handle changes in the selection of the language:

 

f1.selectedLang.onchange = function (event)
	{
		
	switch (event.target.value) {
  case 'Fr':
    vk.setLayout(KeyboardLayout.create(layoutDefFr));
    break;
  case 'De':
  vk.setLayout(KeyboardLayout.create(layoutDefDe));
  break;
  case 'Es':
    vk.setLayout(KeyboardLayout.create(layoutDefEs));
    break;	
    } 
 }

When the user chooses one of our custom layouts we create a keyboard layout with the appropriate layoutDef object.

Next we handle the onfocus and onblur events with the methods showKeyboard() and hideKeyboard(). They just make the div with the keyboard visible or invisible:


function showKeyboard() { 
		
	var x = document.getElementById("keyboard"); 
		x.style.display = "block";			
	}
	
	function hideKeyboard() {
    var x = document.getElementById("keyboard");    
        x.style.display = "none";
    
	}

And that’s all. As you can see creating and loading a custom keyboard with MindFusion JS library is really as easy as 1, 2 3. You can download the complete source code of the sample from this link:

Download the Hidden Keyboard With Special Language Symbols JavaScript Sample

About MindFusion Virtual Keyboard for JavaScript: A highly interactive, highly customizable library written in pure JavaScript that provides your web application with screen typing capabilities similar to those on mobile devices. The keyboard supports three predefined layouts: compact, default and extended. You can also use the keyboard layout creator tool that provides a convenient GUI to create and arrange your own keyboards. The library offers a well documented API with self-explanatory API members and tutorials that guarantee flat learning curve. You can choose among 8 predefined keyboard styles or customize them to create your own styles. Licenses are royalty-free, perpetual with discounts for freelancers, startups, academic institutions to name just a few. Learn more at https://mindfusion.eu/javascript-keyboard.html

Fishbone (Ishikawa) Diagram in WPF

In this blog post we will use the WPF Diagram component to build a fishbone diagram as described in the Wikipedia “Ishikawa diagram” article cited below:

“Ishikawa diagrams (also called fishbone diagrams, herringbone diagrams, cause-and-effect diagrams, or Fishikawa) are causal diagrams created by Kaoru Ishikawa that show the causes of a specific event.

Common uses of the Ishikawa diagram are product design and quality defect prevention to identify potential factors causing an overall effect. Each cause or reason for imperfection is a source of variation. Causes are usually grouped into major categories to identify and classify these sources of variation.” Read more on https://en.wikipedia.org/wiki/Ishikawa_diagram

This tutorial will demonstrate how easy it is to create the same diagram using the WPF diagram library and writing several lines of code. This is the final diagram:

Ishikawa (fishbone) diagram in WPF with MindFusion WPF Diagram library

Ishikawa (fishbone) diagram in WPF with MindFusion WPF Diagram library

I. General Settings

We create an empty WPF project in Visual Studio called “Fishbone”. There we create an Assemblies folder where we place the necessary dll-s:

  • MindFusion.Common.dll
  • MindFusion.Diagramming.Wpf.dll

Then in the MainWindow.xaml file we create a mapping to the Diagramming namespace:

<Window x:Class="Fishbone.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
		xmlns:diag="http://mindfusion.eu/diagramming/wpf"
        Title="MindFusion Fishbone Diagram" Height="387" Width="622">

Then we create the diagram inside the default Grid WPF control:

<Grid>
	<diag:FishboneDiagram x:Name="fdiag" />
</Grid>	

The code creates a new instance of the FishboneDiagram* class with the name “fdiag”. We can use this name to access the object in code.

II. Diagram Data

The FishboneDiagram class exposes an ItemsSource property that provides data for the diagram. The data is an object that contains the label for the main Clause and a list with the labels of the subclauses. We create a special class called FBClause that will represent each fishbone:

public class FBCause
	{
		public FBCause()
		{
			SubCauses = new List();
		}
		public string Label { get; set; }
		public List SubCauses { get; set; }
	}

Next, we create the necessary fishbones this way:

var c1 = new FBCause { Label = "Measurements" };
c1.SubCauses = new List { "Inspectors", "Microscopes", "Calibration" };
…………

Once we are done with all fishbones, we create the model, which will serve as data source for the fdiag object:

var model = new List { c1, c2, c3, c4, c5, c6 };

III. Building the Diagram

Now that the data is ready, we can assign it to the ItemsSource property of the FishboneDiagram class:

fdiag.ItemsSource = model;

We will use the LabelPath and SubCausesPath properties to bind the respective fields of our FBClause objects to the correct data properties of FishboneDiagram:

fdiag.LabelPath = "Label";
fdiag.SubCausesPath = "SubCauses";

If the subclauses of your model were objects instead of strings as in our FBClause class you should use the SubLabelPath property to set the name of the field that will provide data for the subclause labels.

Finally we call the diagram’s ResizeToFitItems method to make sure all fishbones will be visible:

fdiag.ResizeToFitItems(30);

Compile and run the sample and you will see a perfect fishbone diagram.
That’s the end of our tutorial, you can download the sample together with all necessary dll-s from this link:

Download MindFusion Fishbone (Ishikawa) Diagram in WPF Sample

* The FishboneDiagram class will be officially released with the next version of the WPF Diagram Tool.

About Diagramming for WPF: This is the right tool to create flowcharts in WPF that always meet your requirements. The library offers more than 100 predefined node shapes, extensive event set and more than 15 exporters and importers. Each diagram that you build has a completely customizable look through styles, themes and appearance properties for each part of the flowchart. The numerous samples and detailed documentation help you learn quickly how to integrate the component into your own application. You can download the trial version, which has no feature restrictions and does not expire from the WPF Diagram Page on MindFusion website.

Real-Time Chart in WinForms

In this sample we will build a line chart that reads its data in real time and gets updated each second.

Real-time WinForms Chart

We start by creating an empty WinForms project. We assume you have installed the Charting for WinForms component and you can see a list with chart components in the VisualStudio toolbox.

Drag the LineChart control and drop it on the form. You should now see references to the three libraries that you need automatically added to your project:

  • MindFusion.Charting;
  • MindFusion.Charting.WinForms;
  • MindFusion.Common;

1. Series and Data

Our chart will render time stamps at the X-axis. That’s why we choose the DateTimeSeries class to create the series for the chart. The constructor requires two lists – one with DateTime values and one with double values. They provide data for the X and Y axes respectively. We must also provide two more parameters: one for the start and one for the end of the time period.

List<DateTime> dates = new List<DateTime>();
List<double> values = new List<double>();

In order to mimic the real-time functionality we will use a timer. Our timer will generate a random number each second. At the beginning we will have a list with no values. Gradually, we will fill the values and once we reach the count of 100 we will start to delete the first value and add a new value at the end of the arrays.

That’s how we initialize the timer:

Random ran;
ran = new Random();         
        
Timer dataTimer = new Timer();
dataTimer.Tick += new EventHandler(GenerateData);
dataTimer.Interval = 1000;
dataTimer.Start();

Let’s look at the GenerateData method:

private void GenerateData(object sender, EventArgs e)
    {
         dates.Add(DateTime.Now);
         values.Add(2 + ran.NextDouble() * 8.0);

         if (dates.Count > 100)
         {
             dates.RemoveAt(0);
             values.RemoveAt(0);
         }
...
}

There we always add the current DateTime. Since the timer ticks every second that’s exactly what we want. Once the values are 100, we start to remove values at the beginning of the list.

Now let’s create the DateTime series. It requires parameters for the start and end of the period. We always allocate the first and last DateTime values as the bounds of the DateTime data for this series:

DateTimeSeries series = new DateTimeSeries(dates, values, dates[0], dates[dates.Count-1]);

Then we see if we have already added a Series and if so – replace it. If no Series has been added – add the new one:

if (lineChart1.Series.Count > 0)
       lineChart1.Series[0] = series;
else
       lineChart1.Series.Add(series);

By default the DateTimeSeries renders its values from the X-axis – the DateTime instances as labels at the X-axis. We can customize how they look with the DateTimeFormat property. The predefined DateTimeFormat members don’t have an option where the values are rendered as “14:23:34” as a time stamp. So, we choose as DateTimeFormat “CustomDateTime” and use the CustomDateTime to specify the format:

series.DateTimeFormat = DateTimeFormat.CustomDateTime;
series.CustomDateTimeFormat = "H:mm:ss"; 

2. The X-Axis

We want at each moment only the last 10 values to be visible. The other 90 or however they are should be rendered but the user must scroll to see them. We achieve with the MinValue and MaxValue properties of the DateTimeSeries:

series.MinValue = 0;
series.MaxValue = 0.1 * dates.Count;

In order to render only the last 10 series, we use the XAxis properties – MaxValue and MinValue Once the MaxValue of the DateTimeSeries is more than 1, which means that at least 10 values have been added, we adjust the visible range of values at the X-axis so that only the last 10 are visible:

if (series.MaxValue > 1)
  {
      lineChart1.XAxis.MaxValue = series.MaxValue;
      lineChart1.XAxis.MinValue = series.MaxValue - 1.0;
  }

We also set the Title for this axis:

lineChart1.XAxis.Title = "Time";

Let’s hide the numeric values from rendering at the top of the DateTime stamps with the ShowXCoordinates property:

lineChart1.ShowXCoordinates = false; 

3. The Y-Axis

By default the range of an axis is calculated based on the data. Let’s make our chart render the line graphics more to the beginning of the axis by increasing the MaxValue of the Y-axis while we fix the MinValue at 0:

lineChart1.YAxis.MinValue = 0;
lineChart1.YAxis.MaxValue = 20;
lineChart1.YAxis.Interval = 2;

We also change the axis Title and we use NumberFormat property to render the intervals with floating points:

lineChart1.YAxis.Title = "Visitors (in thousands)";
lineChart1.YAxis.NumberFormat = "N";

4. Grid

Let’s render vertical grid stripes. We want them to be dashed and light gray. We use GridType GridColor and GridLineStyle to customize the grid:

lineChart1.GridType = GridType.Vertical;
lineChart1.Theme.GridLineStyle = System.Drawing.Drawing2D.DashStyle.Dash;
lineChart1.Theme.GridLineColor = Color.FromArgb(192, 192, 192);

Note that GridColor and GridLineStyle are properties of the Theme property of LineChart add one extra – stop the grid stripes from moving around when the user scrolls the chart along the axis:

lineChart1.PinGrid = true;

5. Legend

The legend gets its labels from the Title property of a Series. In our case we set:

series.Title = "Server Requests";

We would like to change the legend background to make the legend easier to spot:

lineChart1.Theme.LegendBackground = new MindFusion.Drawing.SolidBrush(Color.FromArgb(120, 230, 230, 230));

We use a semi-transparent brush that let’s chart details be visible when the user moves the legend onto another chart element.

6. Line Colors

We want to render the line in red. We choose the MixedSeriesStyle class as the styling class for our application. You can use any other *SeriesStyle class that is appropriate in your case:

// assign a reb brush for the series
lineChart1.Plot.SeriesStyle = new MixedSeriesStyle()
    {  
         UniformStrokeThickness = 5,
         UniformStroke = new MindFusion.Drawing.SolidBrush(Color.Red),
         UniformFill = new MindFusion.Drawing.SolidBrush(Color.Red)
     };

With that our sample is complete. You can download the full code with the necessary charting dll-s from this link:

Download the WinForms Real-TimeChart Sample

About MindFusion Charting for WinForms: A versatile dashboard component that provides your WinForms application with the ability to create fascinating charts, interactive dashboards and practical gauges. The component combines a flexible API that allows custom combination of chart components to build any type of chart you want. You can add as many axes of any type you want, combine various chart series into a single chart with different data providers each. The control also supports pan and zoom, scroll, unlimited number of legends, grid and a dashboard panel. Linear and oval gauges complete the tool set and guarantee every feature you might need to build the perfect gauge, chart of any type or dashboard in WinForms is right at your fingertips. Learn more at https://mindfusion.eu/winforms-chart.html

Interactive Calendar With Events In JavaScript

In this blog post we will create a Google-like interactive monthly calendar where users will be able to create, edit and delete appointments in real time. We
will use the JavaScript Scheduler. Here is a screenshot of the finished application:

JavaScript Schedule That Mirrors the Google Calendar Features

JavaScript Schedule That Mirrors the Google Calendar Features

And you can run the sample online from this link.

I. Project Setup

We need a reference to the following file to start development:

  • MindFusion.Scheduling.js
  • light.css

The JavaScript file provides the scheduling functionality. The CSS file is responsible for the styling of our calendar. We create a subfolder named “themes” and we place the light.css file there.

We create an HTML file, a blank web page called GoogleSchedule and in the head section we place a reference to the two CSS file:

<link href="themes/light.css" rel="stylesheet" />

 

The reference to the JavaScript file goes at the bottom of the page, right before the closing body tag.

<a href="http://MindFusion.Scheduling.js">http://MindFusion.Scheduling.js</a>

 

We need a element that will represent the calendar, we create one in HTML code and assign it an id:

<div id="calendar" style="height: 100%; width: 100%;"></div>

We want the calendar to take the whole page, that’s why width and height are 100%.

II. Create and Customize the Scheduler

Now we are ready to do the real JavaScript programming of the calendar library. We create an empty JS file called “GoogleSchedule.js” and add a reference to it in the web page, at the bottom:

<a href="http://GoogleSchedule.js">http://GoogleSchedule.js</a>

 

In this JavaScript file we first create a mapping to the MindFusion.Scheduling namespace:

var p = MindFusion.Scheduling;

 

Then we create a Calendar instance using the Calendar DOM element from the web page:

// create a new instance of the calendar 
var calendar = new p.Calendar(document.getElementById("calendar"));

 

We set the calendar view to CalendarView .SingleMonth, which means the calendar shows one month at a time. We also set the theme that we referenced in the CSS file:

calendar.currentView = p.CalendarView.SingleMonth;
calendar.theme = "light";

 

Another customization we make – we use the itemSettings.titleFormat property to add a prefix before each event subject. The prefix is the start time of this event. here is how you set it:

calendar.itemSettings.titleFormat = "%s[hh:mm tt] %h";

 

Finally, we render the calendar:

//visualize the calendar
calendar.render();

 

III. Custom Form

By default, the form that renders when the user clicks on a cell or selection of cells in the calendar allows edit of the dates, but not hours. We will render our custom form, derived from BaseForm to change that. Our form will offer the users a list with hours for the selected dates.

We create a new, empty JavaScript file “TimeForm.js”. There we override the constructor of the BaseForm:

 TimeForm = function (calendar, item, type)
{
	p.BaseForm.call(this, calendar, item);

	this._id = "TimeForm";
	this._type = type;
	this.headerText = "Appointment";
	
}

 

As you can see from the constructor each BaseForm provides data for the calendar and the item that is created or edited. We will use that information later on. We create a prototype of our form and assign the constructor:

TimeForm.prototype = Object.create(p.BaseForm.prototype);
TimeForm.prototype.constructor = TimeForm;

 

TimeForm will be a simple one – it just renders a text area and two combo boxes with the possible hours for the start and end of the appointment. The combo boxes require a list with the members to be rendered. We create a list as a global variable:

var hoursList;

 

Then, in a new method we fill the list with the hours from 12 to 1, divided in intervals of 30 minutes:

// create an array of objects to fill the hours drop-down
TimeForm.prototype.getHourLabels = function ()
{
	hoursList = [];
	hoursList.push({ value: 0, text: "12:00am" });
	hoursList.push({ value: 1, text: "12:30am" });
	
	let index = 1;
	
	for(var i = 1; i &lt; 12; i++)
	{
		hoursList.push({ value: index+1, text: i.toString() + ":00am" });
	    hoursList.push({ value: index+2, text: i.toString() + ":30am" });
		
		index += 2;
	}
	
	//add the first afternnon hours
	hoursList.push({ value: index + 1, text: "12:00pm" });
	hoursList.push({ value: index + 2, text: "12:30pm" });
	
	index += 2;
	
	for(i = 1; i &lt; 12; i++)
	{
		hoursList.push({ value: index+1, text: i.toString() + ":00pm" });
	    hoursList.push({ value: index+2, text: i.toString() + ":30pm" });
		
		index += 2;
	}	
	
	return hoursList;
}

 

The next step is to override the drawContent function of BaseForm:

TimeForm.prototype.drawContent = function ()
{
	p.BaseForm.prototype.drawContent.call(this);

	var content = this.getContent();
.....
}

 

First, we create the text area:

var row = this.row();
	row.innerHTML = this.localInfo.subjectCaption;
	content.appendChild(row);
	
	// create a text-area for the item subject
	var textArea = this.createTextArea({ id: "subject", initValue: this.item.subject, events: { keydown: this._areaKeyDown} });
	textArea.element.style.width = "200px";
	this.addControl(textArea);

	row = this.row();
	row.appendChild(textArea.element);
	content.appendChild(row);

 

Before the text area we place a label with “Subject” on it. The createTextArea method requires several parameters. The first one is the id, then the initial content to be rendered and the events. We want the text area to be 200px wide. The row element places a row of controls in the BaseForm. We use it every time we want to start a new row with elements.

The text area reads its initial content from the value of the subject field in the item object that we receive as reference. After that we create a new row with elements: the drop-down with the hours for the start time:

       // create a drop-down list for start hours
	row = this.row();
	row.innerHTML = "Start Time";
	content.appendChild(row);

	var control = this.createDropDownList({ id: "start_time", items: this.getHourLabels(), initValue: this.getStartTimeIndex(), addEmptyValue: false });
	control.element.style.width = "200px";
	this.addControl(control);

	row = this.row();
	row.appendChild(control.element);
	content.appendChild(row);

 

The code is almost identical to the code for the text area, but here we call the getHourLabels method that returns the array with time values. There is one other new method: getStartTimeIndex(). It’s task is to check the start time of the item and to set the initial value of the drop-down control to that time.

Here is the method:

// get the index of the current item's index to set the value of the startTime drop-down:
TimeForm.prototype.getStartTimeIndex = function ()
{
	if (this.item != null &amp;&amp; this.item.startTime != null)
	{
		
		let index  = this.item.startTime.__getHours() * 2;
		if(this.item.startTime.__getMinutes() &gt; 0)
			index++;
		return index;		
		
	}
	return -1;
}

 

The method checks the hour value of the start time and multiplies it by two because for each hour we show two values in the drop-down: 9:00 and 9:30. If the user has selected half an hour we increment the index with 1.
We use almost the same code to create the endTime drop-down control, so we won’t discuss it here. You can check its code from the download with the source code files for this sample.

Our form needs two buttons – Save and Cancel. We create them in the drawButtons method:

// override BaseForm's drawButtons method to create form buttons
TimeForm.prototype.drawButtons = function ()
{
	var thisObj = this;

	var btnSave = this.createButton({
		id: "btnSave",
		text: this.localInfo.saveButtonCaption,
		events: { "click": function click(e)
		{
			return thisObj.onSaveButtonClick(e);
		}
		}
	});

	var btnCancel = this.createButton({
		id: "btnCancel",
		text: this.localInfo.cancelButtonCaption,
		events: { click: function click(e)
		{
			return thisObj.onCancelButtonClick(e);
		}
		}
	});

	var buttons = this.row();
	buttons.classList.add("mfp-buttons-row");
	buttons.appendChild(btnSave.element);
	buttons.appendChild(btnCancel.element);

	return buttons;
};

 

The BaseForm.createButton() method is similar to the methods that create text area and drop-down lists. We specify here that we will handle the click event for the two buttons. We place the buttons in a new row. Note that you don’t have to call the createButtons function anywhere – it is called automatically by BaseForm.

What happens when the user presses “Save”? Well, we’ll have to read the data from the hour drop-down controls and adjust the start and end time of the newly created Item:

TimeForm.prototype.onSaveButtonClick = function (e)
{
	// update the item with the form data
	 // update the item with the form data
   var startIndex = +this.getControlValue("start_time");
   var startTime = this.item.startTime.date.clone().addHours(startIndex * 0.5);

   var endIndex = +this.getControlValue("end_time");
   var endTime = this.item.endTime.date.clone().addHours(endIndex * 0.5);

   // if end time is specified, decrease it by one day
   if (endIndex != 0 &amp;&amp; this.item.endTime.hour == 0)
    endTime.addDays(-1);

   // check for inconsistent start/end time
   if (startTime.valueOf() &gt; endTime.valueOf())
         endTime = startTime.clone().addHours(1);

   // apply changes 
   this.item.subject = this.getControlValue("subject"); 
   this.item.startTime = startTime;
   this.item.endTime = endTime;

   // if a new item is created, add it to the schedule.items collection
   if (this.type === "new")
     this.calendar.schedule.items.add(this.item);

   // close the form
   this.closeForm();

   // repaint the calendar
   this.calendar.repaint(true);
};

First, we get the value of the startTime drop-down list and we calculate the amount of time to add to the startTime of an Item. A new Item always has a startTime at midnight. Then, we check the number of days the user has selected and calculate how many hours the event actually takes. We assign end time to a copy of the start time and add the calculated event duration to the value. Finally, if the event is new – we add it to the collection of item sin the schedule, if it’s old – we correct its data. Then we close the form and repaint the calendar.

IV. Using the Custom TimeForm

In order to use our custom form we have to add a reference to it in the HTML page, as we did with the other two files:

<script src="TimeForm.js" type="text/javascript"></script>

 

Then we edit the GoogleSchedule.js file First, we need to disable the built-in forms with the useForms property.

// disable this built-in forms for item creation and modification
calendar.useForms = false;

 

Then we have to handle the onSelectionEnd and onItemDoubleClick events to render our form. First, we wire up the events:

// handle the itemDoubleClick event to show the custom form for item editing
calendar.itemDoubleClick.addEventListener(handleItemDoubleClick);

// handle the selectionEnd event to show the custom form for item creation
calendar.selectionEnd.addEventListener(handleSelectionEnd);

 

Then we render the forms, below is the code that shows the TimeForm when a new item is created:

function handleSelectionEnd(sender, args)
{
	// create a new item with the start and end time of the selection
	var item = new p.Item();
	item.startTime = args.startTime;
	item.endTime = args.endTime;
	
	// create and show the custom form
	var form = new TimeForm(sender, item, "new");
	form.showForm();
}

 

We copy the start and end time of the selection from the event arguments. Then we use them in the constructor of the BaseForm.

And that’s the end of this tutorial. Here is a link to download the complete source code of the sample:

Download the Google Calendar in JavaScript Sample

About MindFusion JavaScript Scheduler: MindFusion Js Scheduler is the complete solution for all applications that need to render interactive timetables, event schedules or appointment calendars. Fully responsive, highly customizable and easy to integrate, you can quickly program the JavaScript scheduling library according to your needs. Find out more at https://mindfusion.eu/javascript-scheduler.html