Quantcast
Channel: Syncfusion Blogs
Viewing all 473 articles
Browse latest View live

How-to: Working with Dashboard Filters

$
0
0

This post is part of our on-going how-to series covering the Syncfusion Dashboard Platform. In this entry, we will explore working with Dashboard’s filters. You can watch the full video on our YouTube page.

Dashboard filters help you visualize different combinations of data in a single dashboard. Instead of creating a separate dashboard to visualize subsets of data, the dashboard filters allow you to analyze them within the same view. This post will explain various filtering options like adding a dashboard filter, configuring the master and listener settings, performing cross-data source filtering, and using filter profiles.

You can add filters to a dashboard by dragging the filter elements from the toolbox on the left and dropping them on the design canvas.

You can also use the dedicated filter panel available for configuring filter elements. For more information on filter panels, see our video on YouTube or read its accompanying blog post.
For this example, we’ll build a multi-tab dashboard to display the current statistics of the English Premier League. We’ll have the league standings in one of the tabs and the team statistics in the other, so we can filter out individual teams and analyze their performance.
We have the latest Dashboard Designer and a data source that contains the Premier League Standing details. This is actually a web data source providing us live feeds through REST API. There are details in here like the team name, the logo of the team in the form of URLs, the total number of games played, number of points secured, total number of games won, lost, and quite a bit more. First, let’s rename this data source "Standings."

As you can see in the above GIF, the dashboard builds successfully. It has the Premier League logo, the season details, and a tree map showing the goal statistics. At the bottom are the booking details for the top 10 teams and a grid that shows the standings. We have the team name, the number of games played and won, and the number of points secured by the team. Open the grid configuration with the blue icon at the top-right of the grid card.

In the data section are the columns bound to the widget. Click the settings icon for the "Team name" column and choose Custom sort. Among the advanced sorting options in the pop-up, chooseField, based on points, and the default aggregation type Sum, in Descending order.  


Advanced Sorting Options

ClickApply. Now the best in the league is at the top of the grid.

We’re going to add another dashboard to display the individual team statistics and name it accordingly. A few widgets have been added to this dashboard: at the top, a combo box to filter using team names; on the left, an image widget bound to the field containing the URL for the team logo; and on the bottom, a card widget to show the total number of goals scored by the team.
Click Preview to see how the filtering works.


By default, all the filter elements added to the dashboard will act as a master widget and all the other widgets in the dashboard will act as listener widgets. You can check this using the "Filter configuration" window available through an icon in the toolbar, or by clicking Dashboard and then Filters.


Dashboard Filters Configuration

The master widget is on the left, and is actually a combo box that we have to use to filter out the team name. On the right side are the listener widgets. By default, all the widgets in the dashboard are selected as listener widgets. You can uncheck one if you have to ignore the filter actions. Click Close

You can also make the other nonfilter widgets into master widgets. This works for charts, maps, and grids wherever selection is applicable. So, if you select the grid we added earlier, you can select the check box at the top Act as Master Widget like in the following image.


Act as Master Widget Check Box

Now, opening the Filters Configuration manager, the grid will have been added as a master widget and all the other widgets as listener widgets. Click Preview to see how the filtering works.


As you can see, whenever you select a team name, the filtering will be done and only the filtered values will be shown in the dashboard.

Now, we’re adding another data source called “Results” containing the results of individual games of the league, so we can gather team statistics like goals scored at home, away goals, and others. With the help of this data, we’re going to build individual statistics.
 
In the team statistics dashboard, add a card widget to show the number of goals scored by the team at home. Go back to the data source tab. Click the filter icon for the HomeTeam column and filter out the team name by unchecking (Select All).


Uncheck (Select All)

Doing this, we can summarize the total number of goals scored by the team on home ground. Go back to the dashboard to configure the card widget. In the data section, drag the GoalsHomeTeam column to the Actual Value box. In the properties section, rename the widget Home Goals and center align the title.


Open the filter configuration window. You can see the new card widget in the listener widgets category. But probably, the filter actions won't take place here because the master widget uses a different data source from the listener widget, Home Goals. You can also see at the bottom the relationship between the master and the listener widgets is not established here. To do cross-data source filtering, choose the Custom relationship. Click + and choose teamName as the source column name, Results for the target data source, andHomeTeam for the target column.


Now, the relationship between the master and the listener widgets is established. Commit this by clicking the check mark icon, and then click Update. Check the preview to see the filter action now works as expected.

If you wanted to create the same filters, but for goals made in away games, you would follow all the steps you just took until reaching the Filters Configuration window. You will still see the custom relationship for the Home Goals displayed. You cannot add another relationship to this because filtering both the columns will result in an operation and both columns will be filtered. This is where the filter profiles can be used. By default, a filter profile will be present: rename it “Home” and uncheck Away Goals in the listener widget list.

Click + to add another filter profile, and name it “Away.” For this one, check onlyAway Goals in the listener widget list.


Then create a custom relationship for it like the last one and save it. In the preview, you can see both these cards works as intended.

After adding and configuring more related widgets to the dashboard using these filter profiles, the filters work as shown in the following GIF.


You can also add internal links to your dashboard for easier navigation. For more information on how to do this, please watch our Working with Multi-tabbed Dashboards video or read its accompanying blog post. You can find all the details about the filters applied to your dashboard by clicking the Filters Overview drop-down. 


Filters Overview

We hope this post was helpful. Again, the link to the full video is here. If you aren’t a user of Syncfusion’s Dashboard Platform yet, give it a try with a free, 30-day trial.


Overview of Chart in Xamarin.Forms Part 1

$
0
0

The Syncfusion chart control for Xamarin.Forms can plot more than 25 chart types, ranging from line charts to specialized financial charts. Its rich feature set includes functionalities such as data binding, multiple axes, legends, animation, data labels, annotations, trackball, tooltips, and zooming.

In this blog, we are going to explain how to add the Syncfusion chart reference to your Xamarin.Forms application and configure some basic elements that are required in typical use cases of the chart. It includes creating and binding data to the chart and enabling legend, title, and data labels. The following image represents the final output of the chart we are going to build.


Note: The chart creation and configuration in this blog is explained entirely with XAML code. However, it can also be done in C# code.


Adding the chart reference

The chart reference can be added to a Xamarin.Forms project in different ways. The quickest and easiest way is to add it as a NuGet package. The Syncfusion Xamarin.Forms components are available on nuget.org, so the chart can be installed directly from NuGet just like any other NuGet installation. Follow these steps to add the components from the NuGet server.
  1. Right-click the solution and choose Manage NuGet Packages for Solution.
  2. Select nuget.org from the Package source drop-down.
  3. Search for SfChart using the search box, and then select Syncfusion.Xamarin.SfChart from the search results.
  4. Select all the target platform projects along with the PCL or .NET Standard library from the Projects box.
  5. Install the package.


Refer to the following documentation to learn more about referencing the Syncfusion chart in a Xamarin.Forms application and how to configure it:

https://help.syncfusion.com/xamarin/sfchart/getting-started#adding-chart-reference


Creating a chart

Create an instance of the SfChart class and add it to the layout that suits your requirements. The SfChart class is inherited from View, so you can use all configurations of View in SfChart such as background color, margin, behaviors, animation, and more. The following code sample illustrates how to set the SfChart to be the content of ContentPage and initialize the axes.


After configuring the code, run the app on all targeted platforms to make sure the chart is properly set up and added in the correct position of the screen.


Populating data

Typically, data comes from a server in most real-time applications. The same data can be bound to the chart by specifying the properties of the underlying model. This allows data to be fetched without having to make any duplicate data collection for the chart. Here, we are populating the chart with dummy data to demonstrate how to bind it with the chart and how to specify the binding paths to fetch the data from the model.
public class Model
{
    public string Year { get; set; }

    public double Value { get; set; }
}

public class ViewModel
{
    public List ProductA { get; set; }

    public List ProductB { get; set; }

    public ViewModel()
    {
        ProductA = new List();
        ProductB = new List();

        ProductA.Add(new Model { Year = "2010", Value = 5 });
        ProductA.Add(new Model { Year = "2011", Value = 4.3 });
        ProductA.Add(new Model { Year = "2012", Value = 4.8 });
        ProductA.Add(new Model { Year = "2013", Value = 5.2 });
        ProductA.Add(new Model { Year = "2014", Value = 5.7 });
        ProductA.Add(new Model { Year = "2015", Value = 6.7 });

        ProductB.Add(new Model { Year = "2010", Value = 4.2 });
        ProductB.Add(new Model { Year = "2011", Value = 4.9 });
        ProductB.Add(new Model { Year = "2012", Value = 5.3 });
        ProductB.Add(new Model { Year = "2013", Value = 4.3 });
        ProductB.Add(new Model { Year = "2014", Value = 4.9 });
        ProductB.Add(new Model { Year = "2015", Value = 5.5 });
    }
}
Set the ViewModel instance as the BindingContext of your page. This is done to bind ViewModel properties to SfChart.
Bind the data to the chart and set XBindingPath and YBindingPath properties to fetch the values from the respective properties in the data model to plot the series.

...

Setting a title

The title informs users what to look for in the chart. The text of the title can be set and customized using the Title property of SfChart, as demonstrated in the following code.


Enabling the legend

The legend contains information about the series or data points in a chart. It also allows users to toggle the visibility of series or data points. The value of the Label property of chart series will be displayed in the legend items. In accumulation charts like pie, doughnut, pyramid, and funnel, the series’ x values will be displayed in the legend. The following code is used to enable the legend and set the labels for the series.



Enabling data labels

Data points can be easily annotated with labels to improve the readability of the data. The readability can also be further enhanced by adding markers or customizable symbols. Labels are generally used when the chart has a small amount of data, otherwise the trackball or tooltip features are used to view information about data points for their good performance in more densely populated charts.

 

The following code sample is the complete chart configuration.

The sample can be downloaded here.

In this blog, we kick-started the configuration of the Syncfusion chart control in a Xamarin.Forms application and have shown how easy it is to create and configure a beautiful chart in just a few lines of code. There are many advanced features not discussed here that will help us meet any application requirements.

What’s next

If you’re already a Syncfusion user, you can download the Xamarin setup here. If you’re not yet a Syncfusion user, you can download a free, 30-day trial here. You can also explore the chart samples available on Google Play and the iOS App Store, and learn about advanced features in our documentation.

Part 2 of our overview of the chart in Xamarin.Forms will be coming soon.

If you have any questions or require clarification about this feature, please let us know in the comments below. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

How-To: Working with Images in Dashboards

$
0
0

This post is part of our ongoing how-to series about using the Syncfusion Dashboard Platform. In this post, we’ll review how to use the Dashboard Platform’s image widget. On our YouTube channel you’ll find a full video on this topic.

You can use the image widget to display static images like a company logo as well as dynamic images like the image of a product or salesperson. With the Syncfusion Dashboard Platform, many options are available, and this blog post will demonstrate how to take advantage of them. Note that the information in this post assumes that the Dashboard Designer is installed and up to date.

We’ll begin by adding a new data source by clicking the Add data source button. In the sample data source, we have the sales details of a company in one table and the employee details, including profile images, in another. Next, we create a dashboard to display the sales performance of the employees, renaming the data source "Sales details" and naming the dashboard "Sales performance."

Figure 1: Adding a Data Source

The dashboard is now built and contains a number of details, including total leads, converted leads, and the comparison between the current month and previous month. We have included a combo box filter element, and by making use of it we can choose one salesperson at a time and view the details specific to that salesperson. We’re going to add an image widget in the left corner so that when a salesperson is selected, the corresponding profile picture is displayed.


Figure 2: Adding the Image Widget

The image widget can be found in the Miscellaneous category of the toolbox. Once it’s dragged into place, we can configure the image widget by clicking the Configure button. As mentioned previously, the image widget has the ability to display both static and dynamic images. To display a static image, clear the Bind from database option and select an image using the file picker. Click the Set image button and select the desired image.


Figure 3: Setting a Static Image

The Bind from database option allows us to load dynamic images. Images can be loaded from binary data in our database and from web URLs. In our data source, we have profile pictures as binary data in one of the fields. Returning to the image widget, in the data section, we simply drag and drop the profile field to render the image as we expected.


Figure 4: Setting a Dynamic Image

Back in the dashboard, clicking the Preview button allows us to check how our images are displayed in the Dashboard Viewer. We can select other employees to see that images are dynamically loaded based on the selected salesperson.

Now, let us take a look at the URL option. We can provide the web URL of a desired image and load images dynamically. In our website, we have a profile picture for each employee. As we can see, the URL contains a pattern: the employee ID and the image name. These parameters change for every employee.

We can simply copy this link and paste it into the Pattern text box. Instead of providing a static link, we’re going to replace both fields—that is, the employee ID and the image name—with arguments so that the image can be dynamically changed and the corresponding correct images will be loaded. We’ll edit this and replace the field with arguments in curly braces.


Figure 5: Creating a Dynamic Link Formula

The dynamic link with the pattern is now constructed successfully. In our database, we have the employee ID field as well as the image name in the image link field. Returning to the image widget, we have to provide values for the arguments in the Data section. The first argument is the employee ID, so we can remove that and drag and drop the employee ID field to the correct location. The second argument is the image name. We have it in the image link field, so we can drag and drop it into place. The image is now loaded successfully. Previewing the dashboard again, we can see how our updated images are being rendered, even if we update the salesperson.


Figure 6: Creating a Dynamic Link with a Pattern

If you have the complete hyperlink to the image in the database itself, there is yet another way to display the image. Go to the image widget. In the Pattern text box, provide an empty argument. In the Data section, we can directly add the hyperlink to the column. We can see the image is now rendered.


Figure 7: Adding an Image via Direct Hyperlink

With our images rendered properly, it’s time to publish the dashboard. From the server menu, choose the Publish Dashboard option. Click the Publish button to publish the dashboard. To test the published dashboard, we’ll set another salesperson and check how the image widget is rendered.


Figure 8: Publishing the Dashboard

The Dashboard Designer also provides customizations to modify the image mode. There are several modes available:

  • A default mode in which the image will be preserved in its original size.
  • A fill mode where the image will be stretched across the entire image widget.
  • A uniform mode where the original aspect ratio of the image will be preserved.

You can check out all the mode details in the documentation.

There is also an Ignore filter actions option available. If your image is bound to the database and you want or need to ignore filter actions, you can use this option. Be aware that this may be ineffective if you are loading a static image using the Browse image option.

For more information about Dashboard Platform features, see our documentation. If you have yet to use the Syncfusion Dashboard Platform, try it out with a free, 30-day trial.

Overview of Grid in Essential JS 2: Part 1

$
0
0

The Essential JS 2 grid is a modern, lightweight, feature-rich, and open-source grid for Angular with blazing-fast performance. It has been built using TypeScript with modular architecture, which helps you load only the needed modules on demand.

In this article, we are going to walk you through how to create a grid and inject features such as paging, sorting, filtering, grouping, and aggregation in an Angular application. The final code can be found at our GitHub repository.

Set Up the Development Environment

You need to set up the development environment before creating a grid. Since the source is available in  GitHub and packages are available in npm, you can get started with grid in very few steps.

Creating an Angular Application

To create an Angular application, we need to install Angular CLI globally using the following command.

npm install -g @angular/cli

Then create a new Angular application using the following command.

ng new my-app

This will download all the files we need and initialize the npm install.

Grid Installation through Command Prompt

Once you have created the Angular application, you need to use the following command to install grid.

cd my-app
npm install @syncfusion/ej2-ng-grids --save

--save will save grid in the dependencies of package.json.

Configuring Grid

Now all the configuration related to environment is completed. Next you need to configure grid. Before configuration, we need a component where grid will render. To create an Angular component, you need to use the following Angular CLI command.

ng generate component grid

The new component has been created successfully.

Themes provide life to components. Grid has different themes. They are: 

  •          Material
  •          Office 365
  •          Bootstrap
  •          High Contrast

In this demo application, the material theme will be used for grid. To add the theme, you need to import material.css in styles.css.

@import '../node_modules/@syncfusion/ej2-grids/styles/material.css';

After adding the theme, you need to import grid module in app.module.ts.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { GridComponent } from './grid/grid.component';
import { GridModule } from '@syncfusion/ej2-ng-grids';

@NgModule({
  declarations: [
    AppComponent,
    GridComponent
  ],
  imports: [
    BrowserModule,
    GridModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Creating the Grid Component

We have successfully completed configuration related to grid. Now you need to define your first grid in grid.component.html.

Then add the grid component in app.compnent.html.

Defining Row Data

After creating the grid component, you need to define an array of JavaScript objects.

  this.data = [
      { OrderID: 10248, CustomerID: 'VINET', Freight: 32.38 },
      { OrderID: 10249, CustomerID: 'TOMSP', Freight: 11.61 },
      { OrderID: 10250, CustomerID: 'HANAR', Freight: 65.83 },
      { OrderID: 10251, CustomerID: 'VICTE', Freight: 41.34 },
      { OrderID: 10252, CustomerID: 'SUPRD', Freight: 51.3 },
      { OrderID: 10253, CustomerID: 'HANAR', Freight: 58.17 },
      { OrderID: 10254, CustomerID: 'CHOPS', Freight: 22.98 },
      { OrderID: 10255, CustomerID: 'RICSU', Freight: 148.33 },
      { OrderID: 10256, CustomerID: 'WELLI', Freight: 13.97 },
    ];

Bind the data to the grid using the dataSource property, which accepts an array of JavaScript objects.

Defining Columns as Directives

Grid has an option to define columns as directives. In these column directives, we have properties to customize columns. Let’s check the properties used here:

  •          We have added field to map with a property name an array of JavaScript objects.
  •          We have added headerText to change the title of columns.
  •          We have used textAlign to change the alignment of columns. By default, columns will be left aligned. To change columns to right align, we need to define textAlign as Right.
  •          Also, we have used another useful property, format. Using this, we can format number and date values to standard or custom formats. Here, we have defined it for the conversion of numeric values to currency.

For this demo, we are going to define columns like the following.

Serve the Application

Go to the application directory and launch the server using the following commands.

ng serve –open

Once all the files are compiled successfully, it will serve the site at http://localhost:4200/ .

Grid should look something like this.

Injecting Features

Now, you have the basic working grid with data populated. We are going to learn how to enable some more commonly used built-in features. Before adding these features, we need to define services in providers of app.module.ts. These services will provide a way to access their functionalities from grid.

import { GridModule, PageService, SortService, FilterService, GroupService, AggregateService } from '@syncfusion/ej2-ng-grids';

@NgModule({
  declarations: [
    AppComponent,
    GridComponent
  ],
  imports: [
    BrowserModule,
    GridModule
  ],
  providers: [PageService, SortService, FilterService, GroupService, AggregateService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Paging

Once the PageService is injected in providers, we can gain access to paging functionalities. Also, we need to enable allowPaging in grid to enable the pager.

As of now, default paging is enabled. Now I am going to customize the default pager with pageSettings. Here we defined the pageSettings.pageSize as 3 to define the number of records to be displayed per page.

@Component({
  selector: 'app-grid',
  templateUrl: './grid.component.html',
  styleUrls: ['./grid.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class GridComponent implements OnInit {
  public data: Object[];
  public pageSettings: Object;
  constructor() { }
  ngOnInit() {
    this.data = [
      { OrderID: 10248, CustomerID: 'VINET', Freight: 32.38 },
      { OrderID: 10249, CustomerID: 'TOMSP', Freight: 11.61 },
      { OrderID: 10250, CustomerID: 'HANAR', Freight: 65.83 },
      { OrderID: 10251, CustomerID: 'VICTE', Freight: 41.34 },
      { OrderID: 10252, CustomerID: 'SUPRD', Freight: 51.3 },
      { OrderID: 10253, CustomerID: 'HANAR', Freight: 58.17 },
      { OrderID: 10254, CustomerID: 'CHOPS', Freight: 22.98 },
      { OrderID: 10255, CustomerID: 'RICSU', Freight: 148.33 },
      { OrderID: 10256, CustomerID: 'WELLI', Freight: 13.97 },
    ];
    this.pageSettings = { pageSize: 3 };
  }
}

After enabling paging, grid will be like this:

 

Sorting

After SortService is injected in providers, we need to enable allowSorting in grid to gain its functionalities.

Interact with column headers to sort rows based on columns in either ascending or descending order.


Filtering

Grid has different filter UIs, such as filter bar, filter menu, check box, and Excel-like filters. In this demo application, we are going to use filter menu to filter records. For injecting this filtering feature, we need to define FilterService in providers. Also, to gain filter functionalities and define the filter UI, we need to enable allowFIltering and define filterSettings.type as Menu.

@Component({
  selector: 'app-grid',
  templateUrl: './grid.component.html',
  styleUrls: ['./grid.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class GridComponent implements OnInit {
  public data: Object[];
  public pageSettings: Object;
  public filterSettings: Object;
  constructor() { }

  ngOnInit() {
    this.data = [
      { OrderID: 10248, CustomerID: 'VINET', Freight: 32.38 },
      { OrderID: 10249, CustomerID: 'TOMSP', Freight: 11.61 },
      { OrderID: 10250, CustomerID: 'HANAR', Freight: 65.83 },
      { OrderID: 10251, CustomerID: 'VICTE', Freight: 41.34 },
      { OrderID: 10252, CustomerID: 'SUPRD', Freight: 51.3 },
      { OrderID: 10253, CustomerID: 'HANAR', Freight: 58.17 },
      { OrderID: 10254, CustomerID: 'CHOPS', Freight: 22.98 },
      { OrderID: 10255, CustomerID: 'RICSU', Freight: 148.33 },
      { OrderID: 10256, CustomerID: 'WELLI', Freight: 13.97 },
    ];
    this.pageSettings = { pageSize: 3 };
    this.filterSettings = { type: 'Menu' };
  }
}

After defining the filter menu, the filter UI would be like this:


Grouping

If GroupService is injected in providers, then we need to enable allowGrouping in grid to access its functionalities.

Aggregation

To use aggregation in grid, we need to inject AggregateService. After injecting the service, we need to define aggregations as directives to direct a child of grid. In this demo, we are going to use the Sum built-in aggregate for freight column.

Sum: {{data.Sum}}

After defining aggregation, the total sum is rendered in the footer element of grid.

Summary

In this blog, we have learned how to create a simple grid and enhance its fundamental features using Angular CLI and grid from a node package manager. Grid has a lot of other advanced features, such as data binding with different adaptors, data manipulation (CRUD), column resizing, column choosing, column menu, state persistence, copying to clipboard, responsiveness, and virtualization. There is a lot more we can do with grid! In our next blogs, we can see how easy it is to configure these advanced features.

Feel free to visit the grid source in GitHub, sample browser and documentation to explore live samples of its features and  API. Also be sure to check out the grid sample in GitHub, which is readily runnable, and see just how easy it is to create and configure grid.

If you have any questions or require clarification, please let us know in the comments section.You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

7 ways to compress PDF files in C#, VB.NET

$
0
0

SyncfusionEssential PDF is a .NET PDF library that can be used to optimize or compress your PDF documents. Reducing the PDF file size can help you by optimizing bandwidth cost, network transmission, and digital storage. It is especially useful in areas like archiving, emailing, and using PDF documents in web-based applications. Essential PDF supports the following optimizations:

  • Shrinking all images.
  • Optimizing fonts.
  • Removing metadata.
  • Optimizing page content.
  • Disabling incremental updates.
  • Removing or flattening form fields.
  • Removing or flattening annotations.

In this blog we will look at each of these optimizations and how to implement them.

Reducing PDF file size by shrinking all images

PDF files may contain many images. Removing the images from a PDF file is usually not an option since they are necessary for many PDFs. Downsampling the images will decrease the number of pixels and is possibly the most effective way to reduce PDF file size. The user can control the PDF file size with respect to the quality of the image.

//Create a new compression option object.
PdfCompressionOptions options = new PdfCompressionOptions();
options.CompressImages = true;
//Image quality is a percentage.
options.ImageQuality = 10;

Reducing PDF file size by optimizing fonts

Font resources will also result in large file sizes. Embedded fonts in a PDF document may contain unused glyphs and unwanted font tables—all of which can be removed to make a smaller PDF.
PdfCompressionOptions options = new PdfCompressionOptions();
options.OptimizeFont = true;

Reducing PDF file size by removing metadata

Sometimes metadata in a PDF document will not be needed and can be removed from the PDF file to reduce its size.

PdfCompressionOptions options = new PdfCompressionOptions();
options.RemoveMetadata = true;

Reducing PDF file size by optimizing page contents

Optimizing the page contents will remove unwanted commented lines, white spaces, convert end-of-line characters to spaces and compress all uncompressed contents.

PdfCompressionOptions options = new PdfCompressionOptions();
options.OptimizePageContents = true;

Reducing PDF file size by disabling incremental updates

The content of a PDF file can be updated incrementally without rewriting the entire file. Changes are appended to the end of the file, leaving its original contents intact. Disabling the incremental update will rewrite the entire file, which results in a smaller PDF.

//Load the existing PDF document.
PdfLoadedDocument loadedDocument = new PdfLoadedDocument(@"input.pdf");
//Restructure the complete document.
loadedDocument.FileStructure.IncrementalUpdate = false;

Reducing PDF file size by removing form fields

Removing or flattening form fields can help reduce your file size. When form fields and their values are not necessary, they can be removed. When they are necessary but require no further editing, they can be flattened. Both of these actions will result in a reduced file size. 

public void RemoveFormFields(PdfLoadedDocument ldoc, bool flatten)
{
    if (flatten)
    {
        ldoc.Form.Flatten = true;
    }
    else
    {
        int count = ldoc.Form.Fields.Count;
        for (int i = count - 1; i >= 0; i--)
        {
            ldoc.Form.Fields.RemoveAt(i);
        }
    }
}

Reducing PDF file size by removing annotations

Removing or flattening annotations can help reduce your file size. Annotations and their contents can be removed when they are not needed. When they are necessary but do not require additional editing, they can be flattened. Both of these options will result in a reduced file size.

public void RemoveAnnotations(PdfLoadedDocument ldoc, bool flatten)
{
    foreach(PdfPageBase page in ldoc.Pages)
    {
        if (flatten)
        {
           page.Annotations.Flatten = true;
        }
        else
        {
            int count = page.Annotations.Count;
            for (int i = count - 1;i >= 0; i--)
            {
              page.Annotations.RemoveAt(i);
            }
        }
    }  
}


PDF compression options

A sample demonstrating the available compression options in Essential PDF can be downloaded here: OptimizePDFSample.zip.

Wrapping up

As you can see, Essential PDF provides a variety of optimizing mechanisms for compressing a PDF document. Use them effectively to generate compressed documents for increased efficiency and productivity in a document management system. Take a moment to peruse the documentation, where you’ll find other options and features, all with accompanying code examples.

If you are new to our PDF library, it is highly recommended that you follow our Getting Started guide.

If you’re already a Syncfusion user, you can download the product setup here. If you’re not yet a Syncfusion user, you can download a free, 30-day trial here.

If you have any questions or require clarifications about these features, please let us know in the comments below. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!


Serializing and Deserializing the Pivot Grid for Windows Forms

$
0
0

With the upcoming Essential Studio 2018 Volume 2 release, the serialization and deserialization support will be included in the pivot grid control for WPF. This feature provides extensible support for saving the control’s settings as a stream or as an XML document, and it can be loaded whenever needed. Using this support, pivot grid settings like pivot row items, pivot column items, pivot calculation items, filtered items, sorted items, grouping bar items, conditional format settings, and expand/collapse state of pivot items can be limited with the help of built-in customization options while saving and loading the reports.

Serializing Pivot Grid

The pivot grid control allows the user to save its current settings into a stream or XML document using predefined methods. Let’s see what approaches are available for serializing the control in the immediate sections.

Serialize using save file dialog

Using the Serialize() method, the settings of the pivot grid control can be saved to a desired XML document, and its location can be chosen using save file dialog.

this.pivotGridControl1.Serialize();

Serialize using specific file

Using the Serialize(string filename) method, the settings of the pivot grid control can be saved to a document that is specified using its file name.

this.pivotGridControl1.Serialize("PivotGrid.xml");

Serialize using stream

Using the Serialize(Stream stream) method, the settings of the pivot grid control can be saved to the specified stream.

using (FileStream fileStream = File.Create("PivotGrid.xml"))
{
    this.pivotGridControl1.Serialize(fileStream);
}

Serialize to XML string

Using the SerializeToXml() method, the settings of the pivot grid control can be converted to an XML string which can be preserved for later use.

this.pivotGridControl1.SerializeToXml();

Customizing serialization

By default, all the settings of the pivot grid control are serialized to save in the stream format. Instead of requiring that all settings of the control be saved, a few settings can be saved without considering the others. For example, if the grouping bar's settings are not preferred to save, then the property "SerializeGrouping" of "SerializationOptions" can be set as false to ignore this during serialization, as illustrated in the following code sample.

using (var file = File.Create("PivotGrid.xml"))
{
    SerializationOptions options = new SerializationOptions();
    options.SerializeGrouping = false;
    this.pivotGridControl1.Serialize(file, options);
}

The following chart lists the properties that can be used to ignore required settings during serialization.

PropertyUsage
SerializeSortingTo specify whether sorted items need to be serialized or not.
SerializeFilteringTo specify whether filtered items need to be serialized or not.
SerializeGroupingTo specify whether grouping bar need to be serialized or not.
SerializePivotRowsTo specify whether pivot row items need to be serialized or not.
SerializePivotColumnsTo specify whether pivot column items need to be serialized or not.
SerializePivotCalculationsTo specify whether pivot calculation items need to be serialized or not.
SerializeConditionalFormatsTo specify whether conditional formats need to be serialized or not.
SerializeExpandCollapseStateTo specify whether expand and collapse states need to be serialized or not.

Deserializing Pivot Grid

The pivot grid control allows loading saved settings using predefined methods. Let’s see what approaches are available for deserializing the control in the immediate sections.

Deserialize using open file dialog

Using the Deserialize() method, the settings of the pivot grid control can be restored by selecting the previously saved XML document using the open file dialog.

this.pivotGridControl1.Deserialize();

Deserialize using specific file

Using the Deserialize(string filename) method, the settings of the pivot grid control can be loaded from the specified XML document.

this.pivotGridControl1.Deserialize("PivotGrid.xml");

Deserialize using stream

Using the Deserialize(Stream stream) method, the settings of the pivot grid control can be loaded from the specified file stream.

using (FileStream fileStream = File.OpenRead("PivotGrid.xml"))
{
    this.pivotGridControl1.Deserialize(fileStream);
}

Deserialize from XML string

Using the DeserializeFromXml(string xmlString) method, the control settings stored in the XML string can be loaded into the pivot grid contol.

this.pivotGridControl1.DeserializeFromXml(xmlString);

Customizing deserialization

By default, all settings available in the stream are loaded into the pivot grid control. But the desired settings alone can be loaded by ignoring the rest settings. For example, if the grouping bar's settings are not desired to load in the pivot grid control, then the property "DeserializeGrouping" of "DeserializationOptions" must be set as false to ignore it during deserialization, as illustrated in the following code sample.

using (FileStream fileStream = File.OpenRead("PivotGrid.xml"))
{
    Deserialization­­­­Options options = new DeserializationOptions();
    options.DeserializeGrouping = false;
    this.pivotGridControl1.Deserialize(fileStream, options);
}

The following are the properties that can be used to ignore required settings during deserialization.

PropertyUsage
DeserializeSortingTo specify whether sorted items need to be serialized or not.
DeserializeFilteringTo specify whether filtered items need to be serialized or not.
DeserializeGroupingTo specify whether grouping bar need to be serialized or not.
DeserializePivotRowsTo specify whether pivot row items need to be serialized or not.
DeserializePivotColumnsTo specify whether pivot column items need to be serialized or not.
DeserializePivotCalculationsTo specify whether pivot calculation items need to be serialized or not.
DeserializeConditionalFormatsTo specify whether conditional formats need to be serialized or not.
SerializeExpandCollapseStateTo specify whether expand and collapse states need to be serialized or not.

Serialization and deserialization result in storage and usage of reports anywhere, at any time. In addition to this, the customization options would reduce the amount of serialized and deserialized data during the storage and retrieval process, thus optimizing the performance.

Reference

A sample has been created to demonstrate the serialization and deserialization support in the pivot grid control by customizing its options. Please try the sample and let us know what you think through the comments below.

Add multiselect dropdown into your JavaScript application

$
0
0

Syncfusion Essential JS 2 provides a multiselect component that supports all functionality out of the box to create a Facebook-like multiselect component. This UI enhances the user experience of finding, selecting, and removing items in interactive way, a way which is preferred in almost all apps nowadays. The Essential JS 2 multiselect component is an extended version of HTML select with selection mode, check boxes, sorting, grouping, templates, custom values, etc.

In this blog, you are going to learn how to get started with multiselect component and explore its most important features.

Get started with multiselect component

The multiselect component can be configured by following these steps in TypeScript:

  1. Clone the Essential JS 2 quickstart seed repository and configure the drop-down package in the system.config.js file.
    "@syncfusion/ej2-dropdowns": "syncfusion:ej2-dropdowns/dist/ej2-dropdowns.umd.min.js"
  2. Install the NPM packages using following command.
    $ npm install
  3. Add the HTML input element that needs to be initialized as a component in index.html file.
    <body> <div id='container' style="margin:0 auto; width:250px;"> <input type="text" id='multi-select' /> </div> </body>
  4. Initialize the component in the app.ts file as shown in the following.
    import { MultiSelect } from '@syncfusion/ej2-dropdowns';
    
    // initialize MultiSelect component
    let msObject: MultiSelect = new MultiSelect();
    
    // render initialized MultiSelect
    msObject.appendTo('#multi-select');
    

Populate data

Multiselect is a data-bound component, and can be bound to data from arrays of primitive data, JSON data collections, or remote data sources such as OData, OData V4, URL, and Web API to display data. You can map the data source in the form of DataManager or collection type directly.

To bind remote services, create the DataManager with a service URL and bind it to the component as shown in the following.

import { MultiSelect } from '@syncfusion/ej2-dropdowns';
import { Query, DataManager, ODataAdaptor } from '@syncfusion/ej2-data';

let listObj: MultiSelect = new MultiSelect({
    dataSource: new DataManager({
        url: 'https://js.syncfusion.com/demos/ejServices/Wcf/Northwind.svc/Customers',
        adaptor: new ODataAdaptor,
        crossDomain: true
    }),
    query: new Query().select(['ContactName', 'CustomerID']).take(25),
    fields: { text: 'ContactName', value: 'CustomerID' }
});
listObj.appendTo('#multi-select');

Multiselect with Data 


Configuring selection mode

The selected items can be visualized in a text box with different modes:

  • Default
  • Box (chip)
  • Delimiter
  • Check box

Box (chip)

The selected items are displayed with box (chip) and associated with a close icon. Users can remove each box (chip) with the close button, and can navigate through boxes (chips) using arrow keys. To enable this multiselection mode, set the mode property to Box. How to customize the appearance of a box is described in this documentation section.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    mode:"Box"
});


Multiselect with Box Mode


Delimiter

When selecting multiple items, the selected items can be divided with a desired character as a delimiter. By default, the delimiter character is set to comma. The delimiter character is customizable using the delimiterChar property. To enable this multiselection mode, set the mode property to Delimiter.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    mode:" Delimiter"
});


 Selection with Delimiter Mode


Default

When the component gets focus, the selected items are displayed with Box (chip) mode. Once the component gets focus-out, the selected items are changed with the delimiter.

Component gets focus:

  Component gets focus-in

Component gets focus-out:

  Component gets focus-out

Check box

The multiselect component allows you to select multiple items using check boxes. The list of items populates with check boxes when this mode is enabled. To enable this multiselection mode, set the mode property to CheckBox.

Note: Import the CheckBox module from the ej2-buttons package and CheckBoxSelection from the ej2-dropdowns package to enable this option in multiselect component.

import { MultiSelect,CheckBoxSelection } from '@syncfusion/ej2-dropdowns';
import { CheckBox, ChangeEventArgs } from '@syncfusion/ej2-buttons';
import { Query, DataManager, ODataAdaptor } from '@syncfusion/ej2-data';

MultiSelect.Inject(CheckBoxSelection);

let listObj: MultiSelect = new MultiSelect({
    dataSource: new DataManager({
        url: 'https://js.syncfusion.com/demos/ejServices/Wcf/Northwind.svc/Customers',
        adaptor: new ODataAdaptor,
        crossDomain: true
    }),
    query: new Query().select(['ContactName', 'CustomerID']).take(25),
    fields: { text: 'ContactName', value: 'CustomerID' },
    mode:"CheckBox"
});
listObj.appendTo('#multi-select');


Multiselect with Check Box Mode 


Adding a custom value (tagging)

The user can dynamically add new items with an existing data source. The items don’t have to match exactly with existing pop-up list items. The added new items append at the end of the list. To add a custom value to the existing collection of data, enter the custom value and press the Enter key.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    allowCustomValue: true
});

Multiselect with Custom Value 


Grouping the collection

We can arrange logically related items as groups in a pop-up list. The group’s header is displayed both inline and statically above groups of items. To enable the grouping feature, map the groupBy field on data binding.

import { MultiSelect } from '@syncfusion/ej2-dropdowns';
import { Query, DataManager, ODataAdaptor } from '@syncfusion/ej2-data';

let listObj: MultiSelect = new MultiSelect({
    dataSource: new DataManager({
        url: 'https://js.syncfusion.com/demos/ejServices/Wcf/Northwind.svc/Customers',
        adaptor: new ODataAdaptor,
        crossDomain: true
    }),
    query: new Query().select(['ContactName', 'CustomerID', 'Coun-try']).take(50),
    fields: { text: 'ContactName', value: 'CustomerID', groupBy: 'Country' },
    mode:"Box"
});
listObj.appendTo('#multi-select');

Multiselect with Grouping 


Filter configuration

Data items can be filtered and rebound to the multiselect component. The component provides a way to achieve this:

  1. The filtering is not enabled by default, so enable it by setting allowFiltering to true.
  2. Define the filtering event to filter the data based on parameters.


import { MultiSelect, FilteringEventArgs  } from '@syncfusion/ej2-dropdowns';
import { Query, DataManager, ODataAdaptor } from '@syncfusion/ej2-data';

let listObj: MultiSelect = new MultiSelect({
    dataSource: new DataManager({
        url: 'https://js.syncfusion.com/demos/ejServices/Wcf/Northwind.svc/Customers',
        adaptor: new ODataAdaptor,
        crossDomain: true
    }),
    query: new Query().select(['ContactName', 'CustomerID', 'Coun-try']).take(50),
    fields: { text: 'ContactName', value: 'CustomerID', groupBy: 'Country' },
    mode:"Box",
    allowFiltering: true,
    filtering: function (e: FilteringEventArgs) {
 
    }

});
listObj.appendTo('#multi-select');

Multiselect with Filtered Data


Customization using template

This section explains customizing the default appearance of data items, selected values, group headers, headers, and footers.

Value template

The multiselect component provides the flexibility to customize the visualization of each selected item using a value template. The value template is applicable to customize box appearance.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    valueTemplate:"${ ContactName} - ${ Country}"
});

Selected Item with Template 


Item template

You can specify how every individual item is displayed in a pop-up.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

itemTemplate: "
${ ContactName} -- ${ Country}
", });

List with Item Template 


Header template

You can enable a header section for multiselect’s pop-up, which displays at the top of a pop-up. The headerTemplate property is used to provide header content that accepts both string and HTML content.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    headerTemplate:"NameCity"

});

List with Header 


Footer template

You can include a footer section, which displays at the bottom of multiselect’s pop-up. The footerTemplate property is used to provide footer content that accepts both string and HTML content.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    footerTemplate:" Total list items: 50 "

});

List with Footer 


No records template

When the data source that binds to multiselect component has empty records or no matches found on filtering results, the no records template is displayed in multiselect component. Use the noRecordsTemplate property to define a custom appearance for the no records pop-up.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    noRecordsTemplate: " NO DATA AVAILABLE "

});

Pop-up with No Records Template 


Action failure template

When you bind multiselect component with remote data and the data fetch actions fail, the action failure template is displayed in a pop-up.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    actionFailureTemplate:" Data fetch get fails "

});

 Data Fetch Request Fails


Group template

When the list items are grouped with logical order, a group header is displayed above each group. A group’s header content can be customized using the groupTemplate property.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    groupTemplate:"${City}"

});

List with Customized Group Header 


Customize box (chip) appearance

By default, the chips have styles based on the current applied theme. But you can customize the chip appearance by adding your own CSS classes using the tagging events of multiselect component. Import TaggingEventArgs from the ej2-dropdowns package to configure the tagging event.

let msObj: MultiSelect = new MultiSelect({

    // --- Initialize component with data source, query, and fields

    tagging: (e: TaggingEventArgs) => {

        // Customize code here

    }

});




Conclusion

You have learned how to get started with multiselect component and other important features in this blog. You can learn about this control further in the following resources. Please try multiselect yourself and if you have any questions on using the component, or if you would like to provide feedback, please do so in the comments section.

GitHub source: https://github.com/syncfusion/ej2-dropdowns

Demos: https://ej2.syncfusion.com/demos/#/material/multiselect/default.html

User guide documentation: https://ej2.syncfusion.com/documentation/multi-select/?lang=typescript

 

Syncfusion Attending Microsoft Build Conference 2018

$
0
0

Syncfusion is thrilled to announce that we will be attending the annual Microsoft Build conference this year. Our representatives had a greattime last year, so we’re looking forward to the same again! This year’s conference will be held May 7–9 in Seattle, close to the Microsoft headquarters.

A lot of long-time staff from our N.C. headquarters will be representing Syncfusion, as well as several more developers from our Chennai team. Our engineers will be giving live demonstrations of our products and chatting with attendees, so if you have any questions, you’re welcome to drop by fora conversation. On display will be our latest and greatest, including our new Essential JS 2 suite of pure JavaScript controls, our freshly released Xamarin controls, and our Dashboard Platform.

If you are attending the conference, stop by our booth to check out what’s new and say hello to our team. We’re right near the food hall, at booth S13, so you can drop by after lunch or with your fresh cup of coffee. And, of course, we’ll have free bags, t-shirts, and stickers for you to take home as souvenirs. Let us know in the comments below or on Twitter or Facebook if you’ll be there, and what you’re looking forward to the most!


Adding a Drop-Down List to Your Angular Application

$
0
0

In this blog post, we will look at the Angular drop-down list component in Essential JS 2. You will learn how to get started with a simple drop-down list and move on to enabling several of its features by extending the sample with simple code snippets.

The drop-down list is a text box component that allows a single, non-editable value to be selected from a list of predefined values.

The Essential JS 2 Angular drop-down list component is typically used in an application when you have more than 5 to 10 options and you want to allow users to pick one of them. It has been implemented with features your end users expect, such as searching (including support for diacritical marks), item grouping, cascading selection, accessibility, templating.

Get started with the drop-down list component

The following steps will guide you through the necessary configuration for the drop-down list component in an Angular application.

  1.  Clone the basic Angular sample using following commands.
  2. git clone https://github.com/angular/quickstart.git quickstart
    cd quickstart
    npm install
  3. Install the drop-down list dependencies which are required to render the component in the Angular environment.
  4. npm install @syncfusion/ej2-ng-dropdowns --save
  5. Map the Syncfusion ej2-ng-dropdowns dependency packages in the systemjs.config.js configuration file.
  6. /**
     * System configuration for Angular samples.
     * Adjust as necessary for your application needs.
     */
    (function (global) {
    System.config({
        map: {
            // our app is within the app folder
            app: 'app',
            // angular bundles
            // syncfusion bundles
            '@syncfusion/ej2-base': 'syncfusion:ej2-base/dist/ej2-base.umd.min.js',
            '@syncfusion/ej2-data': 'syncfusion:ej2-data/dist/ej2-data.umd.min.js',
            '@syncfusion/ej2-inputs': 'syncfusion:ej2-inputs/dist/ej2-inputs.umd.min.js',
            '@syncfusion/ej2-popups': 'syncfusion:ej2-popups/dist/ej2-popups.umd.min.js',
            '@syncfusion/ej2-lists': 'syncfusion:ej2-lists/dist/ej2-lists.umd.min.js',
            '@syncfusion/ej2-buttons': 'syncfusion:ej2-buttons/dist/ej2-buttons.umd.min.js',
            '@syncfusion/ej2-dropdowns': 'syncfusion:ej2-dropdowns/dist/ej2-dropdowns.umd.min.js',
            '@syncfusion/ej2-ng-base': 'syncfusion:ej2-ng-base/dist/ej2-ng-base.umd.min.js',
            '@syncfusion/ej2-ng-dropdowns': 'syncfusion:ej2-ng-dropdowns/dist/ej2-ng-dropdowns.umd.min.js'
        }
      });
    })(this);
  7. Import DropDownListModule into the Angular application (app.module.ts) from the package @syncfusion/ej2-ng-dropdowns.
  8. import { NgModule }      from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { AppComponent }  from './app.component';
    import { DropDownListModule } from '@syncfusion/ej2-ng-dropdowns';
    
    @NgModule({
      imports:      [ BrowserModule, DropDownListModule ],
      declarations: [ AppComponent ],
      bootstrap:    [ AppComponent ]
    })
    
  9. Modify the template in the app.component.ts file to render the ejs-dropdownlist component and also include the component theme from the corresponding base package @syncfusion/ej2-dropdowns component through styleUrls.
  10. import { Component, ViewEncapsulation  } from '@angular/core';
    @Component({
      selector: 'my-app',
       // specifies the template string for the drop-down list component
      template: ``,
    })
    export class AppComponent  { name = 'Angular'; }
  11. Import the drop-down list combined CSS files from the Syncfusion package root folder. This can be referenced in your src/styles/styles.css file.
  12. @import '../../node_modules/@syncfusion/ej2-dropdowns/styles/material.css';

Populate data

After initializing, populate the data in the drop-down list using the dataSource property. Here, the retrieval of data from remote data services is performed with the help of the data manager component, so we need to import Query, DataManager, and ODataAdaptor from the ej2-data package.

import { Query, DataManager, ODataAdaptor } from '@syncfusion/ej2-data'
@Component({
  selector: 'my-app',
   // specifies the template string for the drop-down list component
  template: `,

})
export class AppComponent  { 
name = 'Angular'; 
     //bind the DataManager instance to dataSource property
    public data: DataManager = new DataManager({
        url: 'https://js.syncfusion.com/demos/ejServices/Wcf/Northwind.svc/',
        adaptor: new ODataAdaptor,
        crossDomain: true
    });
    // maps the appropriate column to fields property
    public fields: Object = { text: 'ContactName', value: 'CustomerID' };
    //bind the Query instance to query property
    public query: Query = new Query().from('Customers').select(['ContactName', 'CustomerID']).take(6);
    //set the placeholder text for drop-down list input
    public text: string = "Select a customer";
}

Note: The drop-down list loads data either from local data sources or remote data services using the dataSource property.

Group the drop-down list items

We can arrange logically related items as groups in the drop-down list. A group’s header can be displayed both inline and statically above groups of items. To display the grouping header, map the groupBy field on data binding.

Drop-Down List with Grouping

Filter data

When you want to show more options in a drop-down list, users may encounter some difficulty in finding and selecting the option they want. The drop-down list has built-in filtering to solve this problem. It is enabled by setting allowFiltering as true.

@Component({
  selector: 'my-app',
   // specifies the template string for the drop-down list component
  template: ``,
})

Note: You can also apply custom logic to filter items using the filtering event.

Sort data

Sorting allows users to select the correct item from the list of options by arranging the items in ascending or descending order. Use the sortOrder setting and the value Descending or Ascending to enable sorting.

@Component({
  selector: 'my-app',
   // specifies the template string for the DropDownList component
  template: ``
})

Drop-Down List Sorted in Descending Order

Customize appearance using templates

The Essential JS 2 drop-down list has template options for customizing the default UI based on your needs. You can customize all the elements in the drop-down list, such as items, values, headers, and footers.

Item template

The content of each list item within the drop-down list can be customized with the help of the itemTemplate property.

@Component({
  selector: 'my-app',
   // specifies the template string for the drop-down list component
  template: ` {{data.ContactName}} -- {{data.City}}`
})

Drop-Down List with Item Template

Value template

The style of the selected value can be customized using the valueTemplate property.

@Component({
  selector: 'my-app',
   // specifies the template string for the drop-down list component
  template: `{{data.ContactName}}   - {{data.City}}`
})

Drop-Down List with Value Template

Header template

The header element is shown statically at the top of the pop-up, and any custom element can be placed as a header element using the headerTemplate property.

@Component({
  selector: 'my-app',
   // specifies the template string for the drop-down list component
  template: `NameCity`
})

Drop-Down List with Header Template

Footer template

You can place any custom elment as a footer element of the drop-down list pop-up by using the footerTemplate property.

Drop-Down List with Footer Template

Note: The drop-down list also provides noRecordsTemplate, actionFailureTemplate, and groupTemplate. Refer to our documentation for more information.

Conclusion

We hope you found this a useful overview of the drop-down list and its important features. There are other advanced features you can explore in our documentation. If you would like to try the drop-down list component, you can download the free trial or play with our online demo. You can even check out the package on GitHub at https://github.com/syncfusion/ej2-ng-dropdowns. If you have any questions or feedback, please let us know in the comments below. You can also contact us through our support forum or Direct-Trac.

Interview with Introduction to CNTK Succinctly Author James McCaffrey

$
0
0

The following is a short interview with Succinctly series author James McCaffrey, whose book Introduction to CNTK Succinctly was published on Monday, April 9. You can download the book here.


What should people know about Microsoft CNTK? Why is it important?

CNTK is an open source code library from Microsoft that can be used to create deep neural networks and other machine learning models. The idea is that, although it's possible to write deep learning code from scratch, that approach is extremely difficult, so using a library like CNTK is almost a requirement. There are dozens of deep neural libraries but CNTK and Google TensorFlow are the two most sophisticated and powerful. CNTK is written in C++ for performance reasons, but the most common way to use CNTK is through its Python language API.

When did you first become interested in deep learning?

My passion for deep learning began when I was a college student and created a computer program (using the old Pascal language) that predicted NFL professional football scores. I still fire the system (I call it "Zoltar") up every year, and add a new twist or two to experiment with research ideas such as node dropout and optimization algorithms. Before college, I loved to play chess and poker—two activities that are closely related to deep learning.

By writing Introduction to CNTK Succinctly, did you learn anything new yourself?

Heck yes, I learned quite a bit. For example, some of the most challenging problems in machine learning are time series problems where the goal is to predict the value of something at a point in the future, such as a sales amount in six months. In Introduction to CNTK Succinctly I show readers how to tackle a time series problem using an LSTM network ("long short-term memory") in a novel way that uses the LSTM as an ordinary network rather than a sequential memory network.


James McCaffrey

How will Microsoft CNTK and deep learning change over the next few years?

I think the biggest change over the next two to four years will be that basic deep learning techniques, such as deep classifiers and recurrent neural networks, will become standard parts of almost all software developers' personal skill sets. For example, in the mid-1990s most developers didn't know much about web languages such as HTML and JavaScript, but now, most devs have some degree of familiarity with those technologies. In the same way, developers will pick up deep learning skills.

Do you see deep learning as part of a larger trend in software development?

Absolutely. Deep learning, and closely related ideas such as machine learning, data science, and artificial intelligence, are arguably the biggest trend in software development right now. Every company I know is looking to infuse intelligence into some (or even all) of their systems via deep learning. I know at Microsoft, where I work, deep learning is on everybody's mind and all my colleagues are ramping up on these new skills as best they can.

What other books or resources on Microsoft CTNK or deep learning do you recommend?

Because CNTK is so new—version 2 was released in June of 2017, only nine months ago as I talk to you—there are very few CNTK resources available. My go-to resource is the CNTK Python API documentation at https://cntk.ai/pythondocs/cntk.html. That site also has some pretty good examples. For deep learning in general, the gold standard is a set of online videos from Stanford University at https://www.coursera.org/learn/machine-learning.

Overview of Chart in Xamarin.Forms Part 2

$
0
0

This is the continuation of my previous blog "Overview of Chart in Xamarin.Forms Part 1". Hope you enjoyed it and have gained some basic knowledge about to configure the chart in a cross platform Xamarin application. In this blog, we are going to explain about some advanced features that are used for any application requirement. It includes configuring multiple series, annotation, zooming and scrolling, tracking data point, selection, auto scrolling and strip lines.

Adding multiple chart types

Adding multiple types of charts is a typical requirement when you need to plot different units of data to compare trends across a timeline. Let's move forward with an example. I’m going to plot the Target vs Sale of each month using a column chart and show the percentage of achievement using a line chart so that I can display clear information about the trend across six months.


Note: The transposed series (such as bar, stacked bar, and stacked bar 100) cannot be combined with other normal cartesian series and any cartesian series type cannot be combined with accumulation series (pie, doughnut, funnel, and pyramid).

Configuring annotations

Annotations are commonly used to display metadata about a chart or series at a specific point of interest in the plotting area. The control allows you to position them on a chart based on the screen point (pixel coordinate) or chart data. This feature includes functionality like built-in shapes, custom view support, text support to describe an annotation, axis-based plotting, and UI customization. Multiple annotations can be added to a single chart using the Annotations property of chart. In the following example, the top among six students is annotated with view annotation above the column segment.


Enable zooming and scrolling

Zooming and scrolling are useful when you need to visualize large amounts of data. Zooming is performed by pinching, selecting the region, and double tapping at the required position. You can also restrict the zooming and scrolling actions to happen only in a vertical or horizontal direction.


Tracking data point

When there are so many data points plotted in a chart that you cannot enable data markers due to space constraints, you would generally seek an alternate way to view the data values. That is where trackball and tooltip come into play for tracking the data point values. 
The trackball feature is used to track a data point close to the touch contact point. It enables on long press, is draggable across the chart, and will be deactivated with one touch of the finger. 
On the other hand, we have the tooltip feature that displays a pop-up with additional information when the mouse pointer is touching a data point. It is your choice to configure the most suitable feature between trackball and tooltip, or both in the same chart.
 
Following is the example code of trackball and its output.


Following is the example code of tooltip and its output.


Enable data point selection

Interactively select and highlight a data point. This is widely used to navigate to another page with the information of a selected data point or to update the other components in the same page based on the selected data point in a chart.


Configuring autoscrolling

You can configure the autoscrolling feature to focus on a minimal set of data points by visualizing only a few items in the UI and viewing the remaining data points by scrolling. This is typically used in real-time updates to view recently added data points. You need to specify the autoscrolling delta to display a fixed number of points and set the mode to define the position where it should show, the start or end.


Configuring strip lines

Strip lines are used to shade different ranges in a plot area with different colors to improve the readability of a chart. You can annotate them with text to indicate what a particular region indicates. You can also enable the strip lines to be drawn repeatedly at regular intervals—this is useful when you want to mark an event that occurs recursively along the timeline of the chart.


Download the complete sample from here. You can change the MainPage of this sample to the required page to switch between features.

Conclusion

In this blog post, you learned about advanced features available in the Syncfusion chart control for the Xamarin.Forms platform. But there are still a few more features that have not been discussed in this blog. Take look at our documentation to learn about all the features with example codes, or download our sample browser app from Google Play or the iOS App Store to explore the all the samples.
 
If you have any questions or require clarification on these features, please let us know in the comments below. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

Quick Overview of JavaScript Button in Essential JS 2

$
0
0

The Essential JS 2 button component is an advanced version of an HTML button. It is the best alternative for an HTML button since it has all the core functionalities of an HTML button plus advanced features such as different types and predefined styles that are adaptable to different application environments.

The Essential JS 2 button can contain text, icons, or both. The button can also be used to communicate with users through colors, shapes, and images without any text. For example, a button with an image of a magnifying glass almost always represents a search option. A green button almost always represents a successful action, such as a GitHub merge.

This blog post will provide an overview of the Essential JS 2 button, how to configure it, and how to use its advanced features.

Getting started

You need to set up the development environment before creating a button. It is very easy to get started with the button since its source code is available in GitHub and packages are available in npm.

To get started with the button component, you can clone the Essential JS 2 quick-start project using the following commands.

git clone https://github.com/syncfusion/ej2-quickstart.git quickstart
cd quickstart
npm install

The project is preconfigured with common settings (i.e. src/styles/styles.css and system.config.js files) for starting all the Essential JS 2 components.

Configuring the button

Now all configuration related to the environment is completed. Next, we need to configure the button in an application. Add the HTML button tag with an id attribute set as element to your index.html file.

<!DOCTYPE html><html lang="en"><head><title>Essential JS 2</title><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" /><meta name="description" content="Essential JS 2" /><meta name="author" content="Syncfusion" /><link rel="shortcut icon" href="resources/favicon.ico" /><link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /><!--style reference from node_modules/@syncfusion/ej2/--><link href="https://blog.syncfusion.com/styles/styles.css" rel="stylesheet" /><script src="node_modules/systemjs/dist/system.src.js" type="text/javascript"></script><script src="system.config.js" type="text/javascript"></script></head><body><div><!--Element that is going to be rendered--><button id="element">Button</button></div></body></html>


Now let’s initialize the button component in your app.ts file and append it to #element as shown in following code example.

import { Button } from '@syncfusion/ej2-buttons';

// Initialize button component.
let button: Button = new Button();

// Render initialized button.
button.appendTo('#element');

npm start

Run the application in the browser using the previous command to render the button. It should appear as follows.

JavaScript Button

Button component


Themes give components a look and feel that fits the application environment. The Essential JS 2 button supports the following themes:
  • Material 
  • Office 365 
  • Bootstrap 
  • High contrast 
In this demo application, the Material theme will be used for the button.

 

Defining button styles

The button has a predefined set of styles. Each style serves its own purpose. You can style the button by simply adding a class name through its interface. For this demo we are going to create several buttons and style them through classes.

<button id="primarybtn">Primary</button><button id="successbtn">Success</button><button id="infobtn">Info</button><button id="warningbtn">Warning</button><button id="dangerbtn">Danger</button><button id="linkbtn">Link</button>

import { Button } from '@syncfusion/ej2-buttons';
//Primary Button - Used to represent a primary action.
let button: Button = new Button({ cssClass: `e-primary`}, '#primarybtn');
//Success Button - Used to represent a positive action.
button = new Button({ cssClass: `e-success`}, '#successbtn');
//Info Button - Used to represent an informative action.
button = new Button({ cssClass: `e-info`}, '#infobtn');
//Warning Button - Used to represent an action with caution.
button = new Button({ cssClass: `e-warning`}, '#warningbtn');
//Danger Button - Used to represent a negative action.
button = new Button({ cssClass: `e-danger`}, '#dangerbtn');
//Link Button - Changes the appearance of the Button like a hyperlink.
button = new Button({ cssClass: `e-link`}, '#linkbtn');

Predefined Button Styles

Button components with styles 

Creating an icon button

Users tend to perceive visual information better than text. The button can include an icon to add a visual representation of its action. Icons can be added to buttons through their interface. You can customize the icon position to either the left or right side of the button. Icon-only buttons are also supported. In this demo we are going to create a button and load it with different icons.

<button id= 'iconbutton'></button><button id= 'iconleftbtn'>Play</button><button id= 'iconrightbtn'>Stop</button>

import { Button } from '@syncfusion/ej2-buttons';

let button: Button = new Button({iconCss: 'e-icons e-open-icon'}, '#iconbutton');

button = new Button({iconCss: 'e-icons e-play-icon', iconPosition: 'Right'}, '#iconleftbtn');

button = new Button({iconCss: 'e-icons e-stop-icon'}, '#iconrightbtn');

Icon Button

Icon-only button (top), button with icon on left (center), button with icon on right (bottom)

Customization

Buttons also have options for customizing their size, shape, and functionalities:

  • A button’s shape can be customized as a round button, block button, or outline button.
  • Two different sizes are available.
  •  A button can be extended as a toggle button or repeat button by handling event handlers.

In this demo we are going to create different buttons and customize their CSS.

<div class="block"><div class="col-xs-6 col-sm-4 col-lg-4 col-md-4 "><div class="block"><button id='outlinebtn'></button></div><div class="block"><button id='roundbtn'></button></div></div><div class="col-xs-6 col-sm-4 col-lg-4 col-md-4 "><div class="block"><button id='smallbtn'>Small</button></div><div class="block"><button id='normalbtn'>Normal</button></div></div><div class="col-xs-12 col-sm-4 col-lg-4 col-md-4 "><div class="block"><button id="blockbtn">Block Button</button></div><div class="block"><button id="primaryblockbtn">Block Button</button></div></div></div>

import { Button } from '@syncfusion/ej2-buttons';
let button: Button =new Button({cssClass:'e-outline e-primary', content: 'outline'}, '#outlinebtn');
button = new Button({cssClass:'e-round e-primary', iconCss: 'e-icons e-add'}, '#roundbtn');
button = new Button({cssClass: `e-block`});
button.appendTo('#blockbtn');
button = new Button({ isPrimary: true, cssClass: `e-block` });
button.appendTo('#primaryblockbtn');
button = new Button({ cssClass: `e-small`}, '#smallbtn');
button = new Button();
button.appendTo('#normalbtn');


Button types

Buttons with different shapes, sizes, and behaviors

 Conclusion

In this blog, we have looked at how to create a simple button, change its style, and customize its UI and behavior through its properties and CSS. You can download the button sample on GitHub that has been prepared for this blog.

Feel free to view our interactive samples and documentation to explore the other features of the button. If you have any questions or require clarification, please let us know in the comments section below. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

Overview of JavaScript Maps Control in Essential JS 2

$
0
0

The maps control for Essential JS 2 is used to visualize geographical data and represent statistical data of a particular geographic region on Earth. It includes functionalities such as data binding, legends, markers, data labels, tooltips, zooming, and panning. Some of its advanced features include projections, bubbles, animation, color mapping, annotations, navigation lines, and more.

This blog post explores the Syncfusion maps control in Essential JS 2, which allows you to render shapes from provided GeoJSON data. We are going to render a real-time world map and represent the permanent and non-permanent countries in the United Nations Security Council for the year 2017 with various colors, titles, subtitles, legends, and tooltips. The following screenshot depicts the map we will build in this blog.


Map information sourced from Wikipedia

Installation and configuration

The maps control can be configured in TypeScript as follows:

  1. Clone the Essential JS 2 quick-start seed repository, and configure the drop-down package in the system.config.js file.
  2. "@syncfusion/ej2-base""syncfusion:ej2-base/dist/ej2-base.umd.min.js",
    "@syncfusion/ej2-data""syncfusion:ej2-data/dist/ej2-data.umd.min.js",
    "@syncfusion/ej2-buttons""syncfusion:ej2-buttons/dist/ej2-buttons.umd.min.js",
    "@syncfusion/ej2-popups""syncfusion:ej2-popups/dist/ej2-popups.umd.min.js",
    "@syncfusion/ej2-maps""syncfusion:ej2-maps/dist/ej2-maps.umd.min.js",
    "@syncfusion/ej2-pdf-export""syncfusion:ej2-pdf-export/dist/ej2-pdf-export.umd.min.js",
    "@syncfusion/ej2-compression""syncfusion:ej2-compression/dist/ej2-compression.umd.min.js",
    "@syncfusion/ej2-file-utils""syncfusion:ej2-file-utils/dist/ej2-file-utils.umd.min.js"

  3. Install the NPM packages by using the following command.
  4. $ npm install

  5. Add the HTML input element that needs to be initialized as a component in the index.html file.
  6. <body>
    <div id='container'></div>
    </body>

  7. Initialize the component in the app.ts file as shown in the following code.
  8. import { Maps } from'@syncfusion/ej2-maps';
    // initialize maps component
    let map: Maps = new Maps();
    // render initialized maps
    map.appendTo('#container');

Configuring maps with GeoJSON data

After creating the maps component, bind the shape data to render the shapes. Any GeoJSON data can be specified as shape data.

exportlet World_Map: Object =
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "admin": "Afghanistan", "name": "Afghanistan", "continent": "Asia" }, "geometry": { "type": "Polygon", "coordinates": [[[61.21081709172573, 35.650072333309218], [62.230651483005879, 35.270663967422287],
//..
]]}},
//..
]
};

A map built with the maps control is composed of layers, and can accommodate one or more layers. Shape data is bound to maps using the shapeData property in layers.

import { Maps } from'@syncfusion/ej2-maps';
let maps: Maps = new Maps({
layers: [
{
shapeData: World_Map
}
]
});

Bind data source

Define an array of JavaScript objects as a data source to the maps control. This data source will be further used to color the map, display data labels, display tooltips, and more. Assign this to the dataSource property in layers.

exportlet unCountries: object[] = [
{ Country: 'China', Membership: 'Permanent' },
{ Country: 'France', Membership: 'Permanent' },
{ Country: 'Russia', Membership: 'Permanent' },
{ Country: 'United Kingdom', Membership: 'Permanent' },
{ Country: 'United States', Membership: 'Permanent' },
{ Country: 'Bolivia', Membership: 'Non-Permanent' },
{ Country: 'Eq. Guinea', Membership: 'Non-Permanent' },
{ Country: 'Ethiopia', Membership: 'Non-Permanent' },
{ Country: 'Ivory Coast', Membership: 'Permanent' },
{ Country: 'Kazakhstan', Membership: 'Non-Permanent' },
{ Country: 'Kuwait', Membership: 'Non-Permanent' },
{ Country: 'Netherlands', Membership: 'Non-Permanent' },
{ Country: 'Peru', Membership: 'Non-Permanent' },
{ Country: 'Poland', Membership: 'Non-Permanent' },
{ Country: 'Sweden', Membership: 'Non-Permanent' }
];

You should also specify the field names in the shape data and data source to the shapePropertyPath and shapeDataPath properties, respectively. These are used to identify the appropriate shapes and match the specific data source values to them.

For example, consider the color value specified in the data source and the field names specified in shapePropertyPath and shapeDataPath have the same value: ‘Australia’. That color will be applied to the Australia shape.

import { Maps } from'@syncfusion/ej2-maps';
let maps: Maps = new Maps({
layers: [
{
shapeData: World_Map,
dataSource: unCountries,
shapePropertyPath: 'name',
shapeDataPath: 'Country'
}
]
});

Mapping colors

The desired fill colors can be directly specified for shapes. You can also apply colors based on the desired conditions. Here, the field that is used for comparison is specified in the colorValuePath property. If the value of a shape is ‘Permanent’, then the color ‘#EDB46F’ will be applied to the shape. If the value of the shape is ‘Non-Permanent’, the color ‘#F1931B’ will be applied.

import { Maps } from'@syncfusion/ej2-maps';
let maps: Maps = new Maps({
layers: [
{
shapeData: World_Map,
dataSource: unCountries,
shapeDataPath: 'Country',
shapePropertyPath: 'name',
shapeSettings: {
fill: '#E5E5E5',
colorValuePath: 'Membership',
colorMapping: [
{
value: 'Permanent',
color: '#EDB46F'
},
{
value: 'Non-Permanent',
color: '#F1931B'
}
]
}
}
]
});

Define title and subtitle

Specify the appropriate title and subtitle to portray additional information about the map. This can be done by specifying string values to the textproperty in titleSettings and subtitleSettings.

import { Maps } from'@syncfusion/ej2-maps';
let maps: Maps = new Maps({
titleSettings: {
text: 'Members of the UN Security Council',
subtitleSettings: {
text: '- In 2017',
textAlignment: 'Far'
}
}
});

Display legend

Legend items are rendered based on the color mapping values. In our example, this means the legend will be displayed based on the ‘Permanent’ and ‘Non-Permanent’ values specified in the color mapping. You can display the map legend by setting the visible property to true in legendSettings.

import { Maps, Legend } from'@syncfusion/ej2-maps';
Maps.Inject(Legend);
let maps: Maps = new Maps({
legendSettings: {
visible: true
}
});

Enable tooltips

Tooltips can be enabled to display additional information about shapes when the pointer hovers over them. The values displayed in a tooltip can be retrieved from the data source by specifying the data source’s field name in the valuePath property and setting the visible property to true in tooltipSettings.

import { Maps, MapsTooltip} from'@syncfusion/ej2-maps';
Maps.Inject(MapsTooltip);
let maps: Maps = new Maps({
layers: [
{
tooltipSettings: {
visible: true,
valuePath: 'Country'
}
}
]
});

The complete sample code is as follows.

import { Maps, Legend, MapsTooltip } from'@syncfusion/ej2-maps';
import {World_Map} from'./WorldMap';
Maps.Inject(Legend, MapsTooltip);

exportlet unCountries: object[] = [
{ Country: 'China', Membership: 'Permanent' },
{ Country: 'France', Membership: 'Permanent' },
{ Country: 'Russia', Membership: 'Permanent' },
{ Country: 'United Kingdom', Membership: 'Permanent' },
{ Country: 'United States', Membership: 'Permanent' },
{ Country: 'Bolivia', Membership: 'Non-Permanent' },
{ Country: 'Eq. Guinea', Membership: 'Non-Permanent' },
{ Country: 'Ethiopia', Membership: 'Non-Permanent' },
{ Country: 'Ivory Coast', Membership: 'Permanent' },
{ Country: 'Kazakhstan', Membership: 'Non-Permanent' },
{ Country: 'Kuwait', Membership: 'Non-Permanent' },
{ Country: 'Netherlands', Membership: 'Non-Permanent' },
{ Country: 'Peru', Membership: 'Non-Permanent' },
{ Country: 'Poland', Membership: 'Non-Permanent' },
{ Country: 'Sweden', Membership: 'Non-Permanent' }
];

// initialize Maps component
let map: Maps = new Maps({
titleSettings: {
text: 'Members of the UN Security Council',
subtitleSettings: {
text: '- In 2017',
alignment: 'Far'
}
},
legendSettings: {
visible: true
},
layers: [
{
shapeData: World_Map,
dataSource : unCountries,
shapePropertyPath: 'name',
shapeDataPath: 'Country',
tooltipSettings: {
visible: true,
valuePath: 'Country'
},
shapeSettings: {
fill: '#E5E5E5',
colorValuePath: 'Membership',
colorMapping: [
{
value: 'Permanent',
color: '#EDB46F'
},
{
color: '#F1931B',
value: 'Non-Permanent'
}
]
}
}
]
});

// render initialized Map
map.appendTo('#container');

An interactive version of this sample is available on StackBlitz: https://stackblitz.com/edit/wvprqu?file=index.ts

Conclusion

In this blog, we hope that you have learned how to create a simple map and enhance its basic features. The maps control has many advanced features, such as rendering for other map providers, custom shapes, projections, markers, data labels, bubbles, animations, navigation lines, and user-interactive features such as zooming and panning, selection, highlighting, and drill-down. In future blogs we will see how easy it is to configure some of these advanced features.

If you have any questions or need any clarifications, please let us know in the comments section below. You can also contact us through our support forum or Direct-Trac. We are always happy to assist you!

Helpful links

Create Excel 2016 Chart Types in C#

$
0
0

Microsoft Excel 2016 introduced new chart types for exploring and quickly visualizing common financial, statistical, and hierarchical data. These new charts are:

 

·        Waterfall

·        Histogram

·        Pareto

·        Box and whisker

·        Tree map

·        Sunburst

·        Funnel

 

Essential XlsIO, our file-format manipulation library, supports creating and editing these new chart types from version 14.3 onwards. These chart types can be converted to images and exported to PDF.

 

In this blog post we’ll see how to create each of these new chart types in C#.

Waterfall chart

 

A waterfall chart helps viewers quickly understand the finances of business owners by visualizing profit and loss statements. With a waterfall chart, you can quickly illustrate the line items in your financial data and get a clear picture of how each item is impacting your bottom line.

 

A complete sample that creates a waterfall chartcan be downloaded here.


The example shows the income statement of a company where the incomes and expenses are listed and visualized in the chart. Among the expenses, it is clear to see that the fixed costs cut most of the net revenue.




The following code example illustrates how to create a waterfall chart in C# using XlsIO.

 

using (ExcelEngine excelEngine = new ExcelEngine())

{

IApplication application = excelEngine.Excel;

application.DefaultVersion = ExcelVersion.Excel2016;

IWorkbook workbook = application.Workbooks.Open("Sample.xlsx", ExcelOpenType.Automatic);

IWorksheet sheet = workbook.Worksheets[0];

 

IChartShape chart = sheet.Charts.Add();

 

//Set chart type as waterfall

chart.ChartType = ExcelChartType.WaterFall;

 

//Set data range to the chart from the worksheet

chart.DataRange = sheet["A2:B8"];

 

//Data point settings as total in chart

chart.Series[0].DataPoints[3].SetAsTotal = true;

chart.Series[0].DataPoints[6].SetAsTotal = true;

 

//Showing the connector lines between data points

chart.Series[0].SerieFormat.ShowConnectorLines = true;

 

//Set the chart title

chart.ChartTitle = "Company Profit (in USD)";

 

//Formatting data label and legend option

chart.Series[0].DataPoints.DefaultDataPoint.DataLabels.IsValue = true;

chart.Series[0].DataPoints.DefaultDataPoint.DataLabels.Size = 8;

chart.Legend.Position = ExcelLegendPosition.Right;

 

workbook.SaveAs("Waterfall.xlsx");

}

Histogram

 

A histogram is a column chart that shows the frequency of value appears within a distribution. Each column of the chart is called a bin, which can be changed further to analyze the data.

 

A complete sample that creates a histogramcan be downloaded here.

 

The example shows the data frequency across the heights of students. Here, the horizontal axis represents the height. Each column shows the number of students within a given height range.




The following code example illustrates how to create a histogram in C# using XlsIO.

 

using (ExcelEngine excelEngine = new ExcelEngine())

{

IApplication application = excelEngine.Excel;

application.DefaultVersion = ExcelVersion.Excel2016;

IWorkbook workbook = application.Workbooks.Open("Sample.xlsx", ExcelOpenType.Automatic);

IWorksheet sheet = workbook.Worksheets[0];


IChartShape chart = sheet.Charts.Add();


//Set chart type as histogram      

chart.ChartType = ExcelChartType.Histogram;


//Set data range in the worksheet  

chart.DataRange = sheet["A1:A15"];


//Category axis bin settings       

chart.PrimaryCategoryAxis.BinWidth = 8;


//Gap width settings

chart.Series[0].SerieFormat.CommonSerieOptions.GapWidth = 6;


//Set the chart title and axis title

chart.ChartTitle = "Height Data";

chart.PrimaryValueAxis.Title = "Number of students";

chart.PrimaryCategoryAxis.Title = "Height";

//Hiding the legend

chart.HasLegend = false;


workbook.SaveAs("Histogram.xlsx");

}

Pareto chart

 

A Pareto chart is a sorted histogram where columns are sorted in descending order and a line representing the cumulative total percentage is plotted over top.

 

A complete sample that creates a Pareto chartcan be downloaded here.

 

The example shows personal expenses in a sorted format. The line graph shows how each column or issue contributes to the overall total expenses. Notice from the bar graph that the rent category at 2300 was the highest expense. From the green line graph, we see that rent contributed to 40% of all other expenses.




The following code example illustrates how to create a Pareto chart in C# using XlsIO.


using (ExcelEngine excelEngine = new ExcelEngine())

{

IApplication application = excelEngine.Excel;

application.DefaultVersion = ExcelVersion.Excel2016;

IWorkbook workbook = application.Workbooks.Open("Sample.xlsx", ExcelOpenType.Automatic);

IWorksheet sheet = workbook.Worksheets[0];


IChartShape chart = sheet.Charts.Add();


//Set chart type as Pareto

chart.ChartType = ExcelChartType.Pareto;


//Set data range in the worksheet  

chart.DataRange = sheet["A2:B8"];


//Set category values as bin values  

chart.PrimaryCategoryAxis.IsBinningByCategory = true;


//Formatting Pareto line     

chart.Series[0].ParetoLineFormat.LineProperties.ColorIndex = ExcelKnownColors.Bright_green;


//Gap width settings

chart.Series[0].SerieFormat.CommonSerieOptions.GapWidth = 6;


//Set the chart title

chart.ChartTitle = "Expenses";


//Hiding the legend

chart.HasLegend = false;


workbook.SaveAs("Pareto.xlsx");

}

Box and whisker chart

A box and whisker chart shows a distribution of data into quartiles, highlighting the mean and outliers. One use case is to easily identify the minimum and maximum difference in data for a specific product from different companies. Box and whisker charts are most commonly used in statistical analysis.

 

A complete sample that creates a box and whisker chartcan be downloaded here.

 

The example shows the yearly sales of different vehicle types from four different companies. This type of chart visualizes which vehicle type is leading in sales.




The following code example illustrates how to create a box and whisker chart in C# using XlsIO.

 

using (ExcelEngine excelEngine = new ExcelEngine())

{

IApplication application = excelEngine.Excel;

application.DefaultVersion = ExcelVersion.Excel2016;

IWorkbook workbook = application.Workbooks.Open("Sample.xlsx", ExcelOpenType.Automatic);

IWorksheet sheet = workbook.Worksheets[0];


IChartShape chart = sheet.Charts.Add();


//Set the chart title

chart.ChartTitle = "Yearly Vehicle Sales";


//Set chart type as box and whisker

chart.ChartType = ExcelChartType.BoxAndWhisker;


//Set data range in the worksheet

chart.DataRange = sheet["A1:E17"];


//Box and whisker settings on first series

IChartSerie seriesA = chart.Series[0];

seriesA.SerieFormat.ShowInnerPoints = false;

seriesA.SerieFormat.ShowOutlierPoints = true;

seriesA.SerieFormat.ShowMeanMarkers = true;

seriesA.SerieFormat.ShowMeanLine = false;

seriesA.SerieFormat.QuartileCalculationType = ExcelQuartileCalculation.ExclusiveMedian;


//Box and whisker settings on second series  

IChartSerie seriesB = chart.Series[1];

seriesB.SerieFormat.ShowInnerPoints = false;

seriesB.SerieFormat.ShowOutlierPoints = true;

seriesB.SerieFormat.ShowMeanMarkers = true;

seriesB.SerieFormat.ShowMeanLine = false;

seriesB.SerieFormat.QuartileCalculationType = ExcelQuartileCalculation.InclusiveMedian;


//Box and whisker settings on third series  

IChartSerie seriesC = chart.Series[2];

seriesC.SerieFormat.ShowInnerPoints = false;

seriesC.SerieFormat.ShowOutlierPoints = true;

seriesC.SerieFormat.ShowMeanMarkers = true;

seriesC.SerieFormat.ShowMeanLine = false;

seriesC.SerieFormat.QuartileCalculationType = ExcelQuartileCalculation.ExclusiveMedian;


workbook.SaveAs("Box and Whisker.xlsx");

}

Tree map chart

 

A tree map chart provides a hierarchical view of data and makes it easy to spot patterns. The tree branches are represented by rectangles and each sub-branch is shown as a smaller rectangle. Here, the chart displays categories by color and proximity and can easily show lots of data that would be difficult to visualize with other chart types.

 

A complete sample that creates a tree map chartcan be downloaded here.

 

The example charts the areas of different countries. This chart can be used to find the best item across various categories.




The following code example illustrates how to create a tree map chart in C# using XlsIO.

 

using (ExcelEngine excelEngine = new ExcelEngine())

{

IApplication application = excelEngine.Excel;

application.DefaultVersion = ExcelVersion.Excel2016;

IWorkbook workbook = application.Workbooks.Open("Sample.xlsx", ExcelOpenType.Automatic);

IWorksheet sheet = workbook.Worksheets[0];


IChartShape chart = sheet.Charts.Add();


//Set chart type as tree map

chart.ChartType = ExcelChartType.TreeMap;


//Set data range in the worksheet

chart.DataRange = sheet["A2:C11"];


//Set the chart title

chart.ChartTitle = "Area by countries";


//Set the tree map label option

chart.Series[0].SerieFormat.TreeMapLabelOption = ExcelTreeMapLabelOption.Banner;


//Formatting data labels     

chart.Series[0].DataPoints.DefaultDataPoint.DataLabels.Size = 8;


workbook.SaveAs("Treemap.xlsx");

}

Sunburst chart

 

A sunburst chart provides a hierarchical view of data where each level of the hierarchy is represented by one ring or circle, with the innermost circle as the top of the hierarchy.

 

A complete sample that creates a sunburst chartcan be downloaded here.

 

The sample uses the sunburst chart to look at a company’s quarterly sales for the year in detail. The data table drills down to a few category levels: quarter, month, and week. When we want to view sales values for specific weeks, the sunburst chart will give us a final outer circle that identifies the weeks for a specific month of a quarter.



Note the size and relationship of the week boxes to their parent month box and quarter box. Each week contributed a portion of the monthly sales, which in turn contributed to the quarterly sales. The sunburst chart accurately represents these contributions.

 

The following code example illustrates how to create a sunburst chart in C# using XlsIO.

 

using (ExcelEngine excelEngine = new ExcelEngine())

{

IApplication application = excelEngine.Excel;

application.DefaultVersion = ExcelVersion.Excel2016;

IWorkbook workbook = application.Workbooks.Open("Sample.xlsx", ExcelOpenType.Automatic);

IWorksheet sheet = workbook.Worksheets[0];


IChartShape chart = sheet.Charts.Add();


//Set chart type as sunburst

chart.ChartType = ExcelChartType.SunBurst;


//Set data range in the worksheet

chart.DataRange = sheet["A1:D16"];


//Set the chart title

chart.ChartTitle = "Sales by annual";


//Formatting data labels     

chart.Series[0].DataPoints.DefaultDataPoint.DataLabels.Size = 8;


//Hiding the legend

chart.HasLegend = false;


workbook.SaveAs("Sunburst.xlsx");

}

Funnel chart 

 

Funnel charts show values across multiple stages in a process.

 

A complete sample that creates a funnel chart can be downloaded here.

 

The example shows the number of sales prospects at each stage in a sales pipeline. Typically, the values decrease gradually, allowing the bars to resemble a funnel.




The following code example illustrates how to create a funnel chart in C# using XlsIO.


using (ExcelEngine excelEngine = new ExcelEngine())

{

IApplication application = excelEngine.Excel;

application.DefaultVersion = ExcelVersion.Excel2016;

IWorkbook workbook = application.Workbooks.Open("Sample.xlsx", ExcelOpenType.Automatic);

IWorksheet sheet = workbook.Worksheets[0];


IChartShape chart = sheet.Charts.Add();


//Set chart type as funnel

chart.ChartType = ExcelChartType.Funnel;


//Set data range in the worksheet

chart.DataRange = sheet.Range["A1:B6"];


//Set the chart title

chart.ChartTitle = "Funnel";


//Formatting the legend and data label option

chart.HasLegend = false;

chart.Series[0].DataPoints.DefaultDataPoint.DataLabels.IsValue = true;

chart.Series[0].DataPoints.DefaultDataPoint.DataLabels.Size = 8;


workbook.SaveAs("Funnel.xlsx");

}


Note: This chart is only available if you have an Office 365 subscription. 

 

Conclusion

 

These new chart types provide a rich set of storytelling tools in Excel that enable you to do more with your data. These charts can be created in just a few lines of code using the Syncfusion Essential XlsIO library. To make them more appealing, various formatting can be done to customize the axis labels, legends, data labels, title, series, and other chart elements.

 

Using Essential XlsIO, you can also create and edit other chart types such as column, line, pie, doughnut, bar, area, scatter, bubble, stock, surface, radar, combination, and more.

 

If you are new to our XlsIO library, it is highly recommended that you follow our Getting Started guide.

 

If you’re already a Syncfusion user, you can download the product setup here. If you’re not yet a Syncfusion user, you can download a free, 30-day trial here.

 

If you have any questions or would like clarifications about this support, please let us know in the comments below. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

Build Better Mobile Apps with Syncfusion and Xamarin Webinar Q&A

$
0
0
On May 3, 2018, Syncfusion hosted the webinar, “Build Better Mobile Apps with Syncfusion and Xamarin,” presented by Aaron Melamed, Syncfusion’s product solutions specialist. Melamed demonstrated how to improve participants’ mobile applications with Syncfusion’s Xamarin controls. The following blog post is the Q&A portion of the webinar. A recording of the webinar can be found on our YouTube page, or you can watch it here:


Q) Are all your Xamarin.Forms controls .NET Standard compatible?          

A) Yes, all our controls are compatible with .NET Standard.

Q) Does Syncfusion offer controls for accessing SQLServer databases, and Excel spreadsheets?   

A) In Xamarin, you can make use of XlsIO for accessing spreadsheets: https://help.syncfusion.com/file-formats/xlsio/getting-started.

Q) We are interested in taking a course on Xamarin—does Syncfusion provide one?        

A) Our monthly webinars would serve as the closest things to a development course we provide. Please check our YouTube channel for all past webinars.

Q) If the PDFs are saved, are they removed automatically or do you need to code the removal?

A) Both with PDF class library and PDF viewer control, we won’t remove the saved copy of the PDF documents. They provide support to save the PDF document to stream; at the application level, the user can save it to storage. 

Q) What is the link to the app used in this webinar?

A)https://github.com/AaronMelamed/Car-Demo-App

Q) Is there a minimum or maximum API version supported by the controls?

A) Yes. Please refer to the following documentation link: https://help.syncfusion.com/xamarin/introduction/system-requirements.

Q) How often do you release controls?

A) We do four major releases every year and a service package release every month.

Q) Is there any roadmap on future new controls for Xamarin?     

A) Yes. Please refer to this page: https://www.syncfusion.com/products/roadmap/xamarin-formshttps://www.youtube.com/user/syncfusioninc/videos.


Overview of the progress bar control in Xamarin.Forms

$
0
0

Introduction

Welcome to a quick walk-through of Syncfusion’s progress bar control for Xamarin.Forms. The progress bar provides a visual indication of the progress of a lengthy task, such as a file download from a website. It includes features such as rectangular and circular bar shapes, determinate and indeterminate states, segmented progress visualization, customized range colors, and animations.

In this blog, you will learn how to add a progress bar into your application and customize its appearance.

Configure the progress bar

Syncfusion Xamarin components are available on nuget.org. The progress bar NuGet package must be installed to add the progress bar to your project. To do so, open Tools> NuGet package manager> Manage NuGet Packages for Solution in Visual Studio, and search for Syncfusion.Xamarin.SfProgressBar. Install the package.

 

                    Installing the Progress Bar NuGet Package

Initialize the progress bar

The following steps explain how to initialize the progress bar control.

1. Import the progress bar namespace in the appropriate page as shown in the following code.
xmlns:progressBar="clr-namespace:Syncfusion.XForms.ProgressBar;assembly=Syncfusion.SfProgressBar.XForms"
2. There are two variants of the progress bar: SfLinearProgressBar and SfCircularProgressBar. These render the progress on a rectangle or circular range, respectively. Add whichever you prefer to your page. 
<!--Using linear progress bar--><progressBar:SfLinearProgressBar Progress="75"/><!--Using circular progress bar--><progressBar:SfCircularProgressBar Progress="75"/>


Linear and Circular Progress Bars

Launching the application on each platform with progress bar

To use the progress bar inside an application, each platform application requires some additional configuration. The configurations vary from platform to platform and are discussed in the following sections.

iOS

To launch the progress bar in iOS, call the SfLinearProgressBarRenderer.Init() or SfCircularProgressBarRenderer.Init() in the FinishedLaunching overridden method of the AppDelegate class after the Xamarin.Forms framework has been initialized and before the LoadApplication is called, as demonstrated in the following code sample.

public override bool FinishedLaunching(UIApplication app, NSDictionary options) 
{ … 
   global::Xamarin.Forms.Forms.Init(); 
   // Add the following line if you are using SfLinearProgressBar. 
   Syncfusion.XForms.iOS.ProgressBar.SfLinearProgressBarRenderer.Init(); 
   // Add the following line if you are using SfCircularProgressBar. 
   Syncfusion.XForms.iOS.ProgressBar.SfCircularProgressBarRenderer.Init(); 
   LoadApplication(new App()); 
   …
} 

Universal Windows Platform (UWP)

To launch the progress bar in UWP, initialize the SfLinearProgressRenderer() or SfCircularProgressBarRenderer() in the MainPage constructor before the LoadApplication is called, as demonstrated in the following code sample.

public MainPage() 
{ … 
   // Add the following line if you are using SfLinearProgressBar. 
   new Syncfusion.XForms.UWP.ProgressBar.SfLinearProgressRenderer(); 
   // Add the following line if you are using SfCircularProgressBar. 
   new Syncfusion.XForms.UWP.ProgressBar.SfCircularProgressBarRenderer(); 
   LoadApplication (new App ()); 
   … 
}

In addition to these configurations, initialize the progress bar assemblies in the App.xaml.cs file in your UWP project as shown in the following code sample. They are required to deploy the application with the progress bar in Release mode in the UWP platform.

// In App.xaml.cs
protected override void OnLaunched(LaunchActivatedEventArgs e)
{…
   if (rootFrame == null)
   {
      List assembliesToInclude = new List();
      // Add the following line if you are using SfLinearProgressBar.   
 assembliesToInclude.Add(typeof(Syncfusion.XForms.UWP.ProgressBar.SfLinearProgressRenderer).GetTypeInfo().Assembly);

     // Add the following line if you are using SfCircularProgressBar.       
 assembliesToInclude.Add(typeof(Syncfusion.XForms.UWP.ProgressBar.SfCircularProgressBarRenderer).GetTypeInfo().Assembly);
      Xamarin.Forms.Forms.Init(e, assembliesToInclude);
   }
   …
}

Android

The Android platform does not require any additional configuration to render the progress bar.

States

Based on the progress estimation, you can configure the progress bar’s two states:

  • Determinate: This is the default state. You can use it when the progress can be estimated.
  • Indeterminate: By enabling the IsIndeterminateproperty, you can change the progress bar state to indeterminate when the progress cannot be estimated or is not being calculated. It can be combined with the determinate mode to let users know that the app is estimating the progress before the actual progress starts.

<!--Using linear progress bar--><progressBar:SfLinearProgressBar  x:Name="LinearProgressBar" IsIndeterminate="True" /><!--Using circular progress bar--><progressBar:SfCircularProgressBar x:Name="CircularProgressBar" IsIndeterminate="True" />
// Using linear progress bar.
this.LinearProgressBar.IsIndeterminate = true;
// Using circular progress bar.
this.CircularProgressBar.IsIndeterminate = true;

An optional feature of the determinate state is the buffer. This state allows you to visualize the secondary task progress using a secondary progress indicator when the primary task depends on the secondary task. 

<progressBar:SfLinearProgressBar x:Name="LinearProgressBar" Progress="25" SecondaryProgress="75"> </progressBar:SfLinearProgressBar>
this.LinearProgressBar.Progress = 25;
this.LinearProgressBar.SecondaryProgress = 75;
                                                                     

   Progress Bar with Buffer State

Segments

To visualize the progress of multiple sequential tasks, a progress bar can be divided into multiple segments using the SegmentCountproperty.

<!--Using linear progress bar--><progressBar:SfLinearProgressBar x:Name="LinearProgressBar" Progress="25" SegmentCount="4" /><!--Using circular progress bar--><progressBar:SfCircularProgressBar x:Name="CircularProgressBar" Progress="25" SegmentCount="7" />
// Using linear progress bar.
this.LinearProgressBar.SegmentCount = 4;
// Using circular progress bar.
this.CircularProgressBar.SegmentCount = 7;


Linear and Circular Progress Bars with Segments 

Additionally, you can adjust the size of the gaps between the segments using the GapWidth property as shown in the following code.

<!--Using linear progress bar--><progressBar:SfLinearProgressBar x:Name="LinearProgressBar" Progress="25" SegmentCount="4" GapWidth="5" /><progressBar:SfCircularProgressBar x:Name="CircularProgressBar" Progress="25" SegmentCount="7" GapWidth="10" />
// Using linear progress bar.
this.LinearProgressBar.GapWidth = 5;
// Using circular progress bar.
this.CircularProgressBar.GapWidth = 10;

                                                        

Linear and Circular Progress Bars with Modified Segment Gap 

Custom angle

It is even possible to change the circle shape to a semicircle or arc by customizing the start and sweep angles of a circular progress bar using the StartAngle and EndAngle properties in the SfCircularProgressBar, as shown in the following code sample.

<progressBar:SfCircularProgressBar x:Name="CircularProgressBar" Progress="75" StartAngle="180" EndAngle="360"> </progressBar:SfCircularProgressBar>
SfCircularProgressBar circularProgressBar = new SfCircularProgressBar();
circularProgressBar.Progress = 75;
circularProgressBar.StartAngle = 180;
circularProgressBar.EndAngle = 360;
                                                          

Circular Progress Bar with Modified Start and Sweep Angles

Custom content

Using the Contentproperty, you can add any view to the center of the circular progress bar. This feature can be used to indicate the completion of the progress; add start, pause, or cancel buttons to control the progress interactively; add an image that indicates the actual task in progress; add custom text that conveys how much of the task is completed; and more.

The following code sample demonstrates adding custom content to a circular progress bar.

<progressBar:SfCircularProgressBar x:Name="CustomContentCircularProgressBar" Progress="23" HorizontalOptions="Center"><progressBar:SfCircularProgressBar.Content><Grid><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="*"/></Grid.RowDefinitions><Label x:Name="CustomContentProgressBarLabel" Grid.Row="0" BindingContext="{x:Reference CustomContentCircularProgressBar}"
                           TextColor="#007cee" Text="{Binding Progress,StringFormat='{0}%'}" HorizontalTextAlignment="Center" VerticalTextAlignment="End">                       </Label><Label Grid.Row="1" TextColor="#007cee" Text="used" VerticalOptions="Start" Margin="0,-5,0,0" HorizontalTextAlignment="Center" VerticalTextAlignment="Start"></Label></Grid></progressBar:SfCircularProgressBar.Content></progressBar:SfCircularProgressBar>
SfCircularProgressBar circularProgressBar = new SfCircularProgressBar();
circularProgressBar.Progress = 23;
Grid grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(3, GridUnitType.Star) });
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
Label label = new Label();
label.BindingContext = circularProgressBar;
Binding binding = new Binding();
binding.Path = "Progress";
binding.StringFormat = "{0}%";
label.SetBinding(Label.TextProperty, binding);
label.HorizontalTextAlignment = TextAlignment.Center;
label.VerticalOptions = LayoutOptions.End;
label.FontSize = 10;
label.TextColor = Color.FromHex("007cee");
Grid.SetRow(label, 0);
grid.Children.Add(label);
Label textLabel = new Label();
textLabel.Text = "used";
textLabel.HorizontalTextAlignment = TextAlignment.Center;
textLabel.VerticalOptions = LayoutOptions.Start;
textLabel.FontSize = 10;
textLabel.TextColor = Color.FromHex("007cee");
Grid.SetRow(textLabel, 1);
grid.Children.Add(textLabel);
circularProgressBar.Content = grid;
 


Circular Gauge with Custom Content

Appearance

Visualize multiple ranges

You can also visualize multiple ranges with different colors that are mapped to each range to enhance the readability of the progress bar.

The colors can be mapped to specific ranges using the RangeColors property in the linear progress bar. It holds the collection of RangeColor.

The following code sample illustrates mapping solid colors to the ranges in the linear progress bar.

<progressBar:SfLinearProgressBar Progress="100"><progressBar:SfLinearProgressBar.RangeColors><progressBar:RangeColorCollection><progressBar:RangeColor Color="#00bdaf" Start="0" End="25"/><progressBar:RangeColor Color="#2f7ecc" Start="25" End="50"/><progressBar:RangeColor Color="#e9648e" Start="50" End="75"/><progressBar:RangeColor Color="#fbb78a" Start="75" End="100"/></progressBar:RangeColorCollection></progressBar:SfLinearProgressBar.RangeColors></progressBar:SfLinearProgressBar>
SfLinearProgressBar linearProgressBar = new SfLinearProgressBar();
linearProgressBar.Progress = 100;
linearProgressBar.RangeColors.Add(new RangeColor() 
                                 { 
                                   Color = Color.FromHex("00bdaf"), 
                                   Start = 0, End = 25 
                                 });
linearProgressBar.RangeColors.Add(new RangeColor() 
                                 { 
                                   Color = Color.FromHex("2f7ecc"), 
                                   Start = 25, End = 50 
                                 });
linearProgressBar.RangeColors.Add(new RangeColor() 
                                 { 
                                   Color = Color.FromHex("e9648e"), 
                                   Start = 50, End = 75 
                                 });
linearProgressBar.RangeColors.Add(new RangeColor() 
                                 { 
                                   Color = Color.FromHex("fbb78a"), 
                                   Start = 75, End = 100 
                                 });


Linear Progress Bar with Range Colors

You can enable the IsGradientproperty in the RangeColor instance to apply a gradient transition effect to the color as shown in the following code sample.

<progressBar:SfLinearProgressBar Progress="100"><progressBar:SfLinearProgressBar.RangeColors><progressBar:RangeColorCollection><progressBar:RangeColor IsGradient="True" Color="#88A0D9EF" Start="0" End="25"/><progressBar:RangeColor IsGradient="True" Color="#AA62C1E5" Start="25" End="50"/><progressBar:RangeColor IsGradient="True" Color="#DD20A7DB" Start="50" End="75"/><progressBar:RangeColor IsGradient="True" Color="#FF1C96C5" Start="75" End="100"/></progressBar:RangeColorCollection></progressBar:SfLinearProgressBar.RangeColors>
SfLinearProgressBar linearProgressBar = new SfLinearProgressBar();
linearProgressBar.Progress = 100;
linearProgressBar.RangeColors.Add(new RangeColor() 
                                 { 
                                   Color = Color.FromHex("88A0D9EF"), 
                                   IsGradient = true, 
                                   Start = 0 , End = 25 
                                 });
linearProgressBar.RangeColors.Add(new RangeColor() 
                                 { 
                                   Color = Color.FromHex("AA62C1E5"), 
                                   IsGradient = true, 
                                   Start = 25, End = 50 
                                 });
linearProgressBar.RangeColors.Add(new RangeColor() 
                                 { 
                                   Color = Color.FromHex("DD20A7DB"), 
                                   IsGradient = true, 
                                   Start = 50, End = 75 
                                 });
linearProgressBar.RangeColors.Add(new RangeColor() 
                                 { 
                                   Color = Color.FromHex("FF1C96C5"), 
                                   IsGradient = true, 
                                   Start = 75, End = 100 
                                 });


Linear Progress Bar with Range Color Gradient

Thickness

You can easily tweak the thickness of the track and progress indicator to render the control with different appearances.

Linear progress bar

Using the TrackHeight and Padding properties, you can customize the height of the track and the progress indicator’s padding in the linear progress bar.

<progressBar:SfLinearProgressBar Progress="100" TrackHeight="10" Padding="2"></progressBar:SfLinearProgressBar>
SfLinearProgressBar linearProgressBar = new SfLinearProgressBar();
linearProgressBar.Progress = 100;
linearProgressBar.TrackHeight = 10;
linearProgressBar.Padding = 2;


Linear Progress Bar with Custom Padding and Thickness

Circular progress bar

In the circular progress bar, you can customize the thickness using the following properties:

 The following code sample shows how to customize the thickness in a circular progress bar.

<progressBar:SfCircularProgressBar x:Name="TrackOutsideProgressBar" Progress="75" IndicatorOuterRadius="0.7" IndicatorInnerRadius="0.65" ShowProgressValue="False"></progressBar:SfCircularProgressBar>
SfCircularProgressBar trackOutsideProgressBar = new SfCircularProgressBar();
trackOutsideProgressBar.Progress = 75;
trackOutsideProgressBar.IndicatorOuterRadius = 0.7;
trackOutsideProgressBar.IndicatorInnerRadius = 0.65;
trackOutsideProgressBar.ShowProgressValue = false;


Circular Progress Bar with Custom Padding and Thickness

Corner radius

You can customize the corner radius of the progress bar by using the CornerRadius property in the linear progress bar.

<progressBar:SfLinearProgressBar Progress="50" TrackHeight="10" CornerRadius="10"></progressBar:SfLinearProgressBar> 
SfLinearProgressBar linearProgressBar = new SfLinearProgressBar();
linearProgressBar.Progress = 50;
linearProgressBar.CornerRadius = 10;


Linear Progress Bar with Custom Corner Radius

Colors

You can also apply appealing colors to the track and progress indicator to match your app theme. Colors can be customized using the TrackColor and ProgressColor properties as shown in the following code sample.

<progressBar:SfLinearProgressBar Progress="75" TrackColor="#3351483a" ProgressColor="#FF51483a"></progressbar:SfLinearProgressBar>
SfLinearProgressBar linearProgressBar = new SfLinearProgressBar();
linearProgressBar.Progress = 75;
linearProgressBar.ProgressColor = Color.FromHex("FF51483a");
linearProgressBar.TrackColor = Color.FromHex("3351483a"); 


Linear Progress Bar with Custom Colors

 A sample demonstrating the progress bar control and its various features can be downloaded here.

Conclusion

The Syncfusion Xamarin.Forms progress bar control is designed with flexible UI customizations to adapt to your app easily. It includes developer-friendly APIs to increase developer productivity. This control is also available for Xamarin.Android and Xamarin.iOS.

We hope that this component will help satisfy your application development needs and recommend you further explore this control by downloading the sample created specifically for this blog. Syncfusion Xamarin.Forms offers the most comprehensive suite of advanced UI components that work out of the box in all three platforms, providing platform-specific themes and adaptive rendering for all mobile, tablet, desktop form factors.

Try out our products by downloading the free trial setup and explore the samples available on Google Play and the App Store. If you have any questions or feedback, please let us know in the comments below. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

PowerPoint to Image Conversion in UWP

$
0
0

Syncfusion is excited to share that PowerPoint to image conversion is now available for UWP applications from 2018 Volume 1 (version 16.1) onward. Before, Essential Presentation supported PowerPoint to image conversion in Windows Forms, WPF, ASP.NET, and ASP.NET MVC. Now, you can convert PowerPoint presentations (PPTX) to images in UWP. This helps with viewing and printing a PowerPoint presentation from Windows desktop and mobile environments. 

The following slide elements are supported in PowerPoint-to-image conversion:

  • Text
  • Bullets and numbering
  • Shapes
  • Tables
  • Charts
  • Images
  • SmartArt diagrams
  • Formatting

Converting a PowerPoint slide to a high-quality image

Let’s learn how to convert a PowerPoint slide to an image in UWP.

Prerequisites:

  • Windows 10
  • Visual Studio 2015 or 2017
  • Windows 10 SDK

Step 1: Create a Blank App (Universal Windows) and name it PowerPointDemo.


Step 2: Choose the target version (Essential Presentation is supported from the minimum version).


Step 3: Add the Syncfusion.Presentation.UWP NuGet package as a reference to the project from the Syncfusion UWP NuGet feed. For more information about adding a NuGet feed in Visual Studio and installing NuGet packages, refer to our documentation.

You can also install this package from the NuGet package manager console by executing the following command.

Install-package Syncfusion.Presentation.UWP -source http://nuget.syncfusion.com/nuget_universalwindows/nuget/getsyncfusionpackages/universalwindows
Step 4: Add an input PowerPoint document to the asset folder. Right-click the PowerPoint document, select Properties, and set its build action as Embedded resource.

Step 5: Add a button in the MainPage.xaml.

<Pagex:Class="PresentationDemo.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Button Name="ConvertPPTX"HorizontalAlignment="Center"VerticalAlignment="Center"Content="Convert"Click="ConvertPPTX_Click"></Button></Grid></Page>

Step 6: Add the following code in the ConvertPPTX_Click method in the MainPage.xaml.cs file to retrieve the embedded PowerPoint file as stream and convert the PowerPoint slide to an image using the SaveAsImageAsync method of ISlide interface. 

Note: It is mandatory to instantiate the ChartToImageConverter property of IPresentation interface, otherwise the charts will be left blank in the resultant image.

//Get the embedded PowerPoint presentation. You can use a file picker to read a file instead.
Assembly assembly = this.GetType().GetTypeInfo().Assembly;
using (Stream stream =    assembly.GetManifestResourceStream("PowerPointDemo.Assets.Template.pptx"))
{
        //Load the presentation file from stream.
        using (IPresentation _presentation = Presentation.Open(stream))
        {
            //Initialize ‘ChartToImageConverter’ to convert the charts in slides
           _presentation.ChartToImageConverter = new ChartToImageConverter();

            //Get the first slide in the presentation.
            ISlide slide = _presentation.Slides[0];

            //Create a storage file to save the converted image.
            StorageFile sampleFile = await KnownFolders.PicturesLibrary.CreateFileAsync("Slide1.png", CreationCollisionOption.ReplaceExisting);

            //Convert the slide to an image.
            using (var imageStream = await sampleFile.OpenStreamForWriteAsync())
            {
                await slide.SaveAsImageAsync(imageStream);
            }
        }
}

Converting a PowerPoint slide to a thumbnail image

You can also generate images in custom sizes by enabling rendering options. The below code example shows how to convert a PowerPoint slide to a thumbnail image.

//Set the rendering options to scale the image at 0.25. The default scaling factor is 1.
RenderingOptions options = new RenderingOptions() { ScaleX = 0.25f, ScaleY = 0.25f };
//Convert the slide to an image.
using (var imageStream = await sampleFile.OpenStreamForWriteAsync())
{
await slide.SaveAsImageAsync(imageStream);
}

You can also print a PowerPoint presentation by printing the converted images. The images can be printed using the UWP native printer APIs.

A simple PowerPoint viewer UWP application can be downloaded, showing you how to display a slide and print the PowerPoint presentation.


Simple PowerPoint viewer application’s desktop and mobile views

Conclusion

With PowerPoint presentation-to-image conversion, you can achieve the below functionality in UWP applications.

  • Display PowerPoint slides.
  • Print a PowerPoint presentation.

You can convert existing PowerPoint slides or create a slide from scratch and then convert it to an image as required.

If you are new to our Presentation library, we highly recommend you follow our Getting Started guide.

If you’re already a Syncfusion user, you can download the product setup on Direct-Trac. If you’re not yet a Syncfusion user, you can download a free, 30-day trial.

If you have any questions or require clarification about this feature, please let us know in the comments below. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

My Journey in App Development

$
0
0

This guest blog was written by Julie Misson, a Syncfusion customer who is the founder of Make it APPen, a team that designs and creates mobile apps to improve patient care.

I would like to share with you my journey into app development and how Syncfusion ended up being an integral part in this journey.

First, a bit about me. I am a nurse by trade but a nerd by nature. I am 56 years old and a grandmother to three beautiful girls. My interest in app development evolved by having worked in hospitals for over 30 years both as a nurse and in the quality and data fields. During that time, I uncovered four consistent frustrations healthcare professionals have. These frustrations occur thousands of times across Australia every day:

  1. Lack of resources: time, staff, and money.
  2. Out of date and incorrect information.
  3. Delayed treatment.
  4. Disengaged consumers.

The ultimate pain for healthcare professionals is the pervasive feeling that they are not providing the best care for their patients. As late as the 2000s, there was no realistic solution to these frustrations other than more manpower. But with my experience in both technology and health, I saw that an app could go some way to resolve every one of these frustrations—an app that provided correct information, real-time feedback, video education, emergency help buttons, and clear lines of communication.

Four years ago, my journey into app development began. It was not my first coding experience, having produced hundreds of software applications for small businesses, so I had a bit of an idea of what I was getting into.

I spent most of the next three years trying different platforms and types of apps. I originally headed down the purely Apple route, but did not want to limit myself just to Apple. I then investigated various web apps, of which I developed a few. In the end, I decided to go with Xamarin, a Microsoft product. This meant learning two new languages, C# and XAML, but it also meant I could produce native code apps for the three main platforms: Apple, Android, and Windows.

My first major app on the Xamarin platform was beatpain, an app that enables people with chronic pain to rehabilitate themselves. In2ot paid me to build the app, and the content was written by an occupational therapist from in2OT with input from other health experts. This app is now available on Google Play and is waiting for approval from Apple.


Beatpain App

This app really pushed my limits, as it required a graph, a sliding scale, and a carousel, among other things. I needed a product that would make developing these objects easier. These objects also had to be professional looking and easy to format.

Luckily, I discovered Syncfusion, which had products built specifically for Xamarin.

I found Syncfusion easy to install and to use. A couple of times I was stuck on a piece of coding, but I found their help desk amazing. They sent back sample bits of code that I could incorporate into my project. I ended up with an app that met all the needs of my client.

Design temperature monitor using the circular gauge control in Xamarin.Forms

$
0
0

This is another overview series blog in which you are going to get a quick overview of our circular gauge and its features through designing a temperature monitor gauge.

The circular gauge is a data visualization component that helps you visualize numerical values on a circular scale. It has highly customizable features, such as scales, pointers, ranges, and annotations, and allows you to design a dashboard, clock, temperature monitor, speedometer, etc.

To create a temperature monitor, you need the following features in the circular gauge control:

  • ScalesDefine the temperature scale values in numbers from start to end with tick marks. Also used to draw the rim around the gauge.
  • RangesIndicate multiple-colored temperature range levels.
  • PointersPoint out the current temperature value.HeadersDisplay header text.
  • AnnotationsShow the current temperature value.

This section explains how to design a temperature monitor by customizing the appearance of the circular gauge as shown in the following screenshot.


Configuring circular gauge 

Syncfusion’s components for Xamarin.Forms are available on nuget.org. To add SfCircularGauge to your project, open the NuGet package manager in Visual Studio, search for Syncfusion.Xamarin.SfGauge, and then install it.


Launching circular gauge on each platform 

Android launches the circular gauge without any initialization. However, an additional step is required for launching circular gauge in iOS and UWP.

iOS project 

To launch the circular gauge in iOS, create an instance of SfGaugeRenderer in the FinishedLaunching overridden method of AppDelegate class in iOS Project as shown in the following code.
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
    ...
        LoadApplication(new App());
        new Syncfusion.SfGauge.XForms.iOS.SfGaugeRenderer();
    ...
}

UWP project 

To launch the circular gauge in UWP, create an instance of SfGaugeRenderer in the constructor of MainPage in the UWP project as shown in the following code.

public MainPage()
{
   ...
        new Syncfusion.SfGauge.XForms.UWP.SfGaugeRenderer();
    ...
}

Creating a circular gauge 

Circular gauge is entirely configurable in both XAML and code behind. The following steps describe the initialization of the circular gauge control in XAML:

  • Import the following circular gauge control namespace in the XAML page.
<ContentPage
xmlns:gauge ="clr-namespace:Syncfusion.SfGauge.XForms;assembly=Syncfusion.SfGauge.XForms">
  • Create an instance of the circular gauge class and add it to the layout that suits your requirements. The following screenshot depicts the default view of circular gauge when initializing the control. 

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:GuageOverview" xmlns:gauge="clr-namespace:Syncfusion.SfGauge.XForms;assembly=Syncfusion.SfGauge.XForms" x:class="GuageOverview.MainPage"><gauge:SfCircularGauge></gauge:SfCircularGauge></ContentPage>


Scales

Scales contain a collection of scale elements, and you can add any number of circular scales inside the gauge. Scale contains labels and tick marks, the positions and values of which can be customized.

In the temperature monitor, two types of scale elements have been created; one is used to draw the rim around the circular gauge and the other to display temperature labels in numbers from -40 to 150 with tick marks. First, we should create an instance for scale objects and add it to the scales collection in circular gauge.

Scales have two types of tick marks: major and minor ticks. Major ticks have labels and are used to specify the primary value intervals. Minor ticks do not have labels and are used to define the space inside the primary value interval. You can specify the tick’s appearance and position-related properties using the MajorTickSettings and MinorTickSettings properties for scale.

Intervals of label and major ticks can be customized by using the Interval property. Minor ticks can be chosen per interval in scale using the MinorTicksPerInterval property.

You can define the start and end angles of a scale using the StartAngle and SweepAngle properties. The start and end values of the scale can be defined using the StartValue and EndValue properties. The default values of start angle and sweep angle are 130 and 280, and the default values of the start value and end value are 0 and 100.

Customize the position for the scale, ticks, and labels by using corresponding offset properties. Values for offset should be given from 0 to 1 (gauge center position to edge). 

<gauge:SfCircularGauge Margin="20"><gauge:SfCircularGauge.Scales><gauge:Scale ShowRim="True" ScaleStartOffset="1" RimThickness="2"  RimColor="#f2f1f1" ShowLabels="False" ShowTicks="False" StartAngle="0"  SweepAngle="360" /><gauge:Scale ShowRim="False"  StartValue="-40" EndValue="150" LabelOffset="0.55" Interval="10" MinorTicksPerInterval="9"><gauge:Scale.MajorTickSettings><gauge:TickSettings Color="Black" StartOffset="0.85" EndOffset="0.65" Thickness="2"/></gauge:Scale.MajorTickSettings><gauge:Scale.MinorTickSettings><gauge:TickSettings Color="Black" StartOffset="0.85" EndOffset="0.75" Thickness="1"/></gauge:Scale.MinorTickSettings></gauge:Scale></gauge:SfCircularGauge.Scales>    </gauge:SfCircularGauge>


Ranges

Ranges contain a collection of range elements. You can add any number of ranges inside the scale. A range of the circular gauge is a visual element that helps you visualize where a value falls on a circular scale.

Ranges in a circular gauge are used to display a temperature range with different color indication. To design the temperature monitor, you should use five ranges for scale to indicate the various levels of temperature.

Every range has start and end values, and these can be specified using the StartValue and EndValue properties.

The length and position of a range can be customized using the outer and inner offset properties as shown in the following code. The outer offset properties are used where the range length starts in scale, and inner offset properties are used where the range length ends.

<gauge:Scale.Ranges><gauge:Range StartValue="-40" EndValue="0" Color="#4f91fa" OuterStartOffset="0.85" OuterEndOffset="0.85" InnerStartOffset="0.65" InnerEndOffset="0.65" /><gauge:Range StartValue="0" EndValue="10" Color="#28bce4" OuterStartOffset="0.85" OuterEndOffset="0.85" InnerStartOffset="0.65" InnerEndOffset="0.65" /><gauge:Range StartValue="10" EndValue="30" Color="#0bbe53" OuterStartOffset="0.85" OuterEndOffset="0.85" InnerStartOffset="0.65" InnerEndOffset="0.65" /><gauge:Range StartValue="30" EndValue="40" Color="#d4d459" OuterStartOffset="0.85" OuterEndOffset="0.85" InnerStartOffset="0.65" InnerEndOffset="0.65" /><gauge:Range StartValue="40" EndValue="150" Color="#ff3233" OuterStartOffset="0.85" OuterEndOffset="0.85" InnerStartOffset="0.65" InnerEndOffset="0.65" /></gauge:Scale.Ranges>

 

Pointers

Pointers contain a collection of pointer elements, and you can add any number of pointers inside the scale. Pointers are used to design the value indication symbol and point out the current temperature value in a temperature monitor.

There are three types of pointers available in gauge: range pointer, needle pointer, and marker pointer. The value of pointer is set by using the Value property.

A marker pointer is used to point out a value with built-in shapes, such as a triangle, inverted triangle, square, diamond, or image.

<gauge:Scale.Pointers><gauge:MarkerPointer MarkerShape="InvertedTriangle" Color="#f7ab9c" Value="22.75" MarkerHeight="20" MarkerWidth="20" Offset="0.85" /></gauge:Scale.Pointers>

 

A range pointer is used to point out the value from the start value of the scale. The length and position of a range can be customized by using the StartOffset and EndOffset properties.

<gauge:Scale.Pointers><gauge:RangePointer Value="22.75" StartOffset="0.45" EndOffset="0.42" Color="#f7ab9c"/></gauge:Scale.Pointers>

 

A needle pointer is used to point out a value with a highly customizable needle-type element. One end of the needle is positioned at the center of the scale and other end is pointing to the scale value.

The knob (rounded ball on the arrow) and tail (rectangle at the end of the knob) elements in needle pointer are used to enhance the pointer’s look. The length of a pointer can be customized using the LengthFactor property.

<gauge:Scale.Pointers ><gauge:NeedlePointer x:Name="pointer" Color="#f7ab9c" Value="22.75" TailLengthFactor="0.19" TailColor="#f7ab9c"  Thickness="8" KnobRadius="16" KnobStrokeColor="#efefef" KnobColor="White" KnobStrokeWidth="7" LengthFactor="0.77" ></gauge:NeedlePointer></gauge:Scale.Pointers >

 

Headers

Headers contain a collection of headers, and you can add any number of headers inside the circular gauge. You can display the text of “Inside,” “Temp,” and “Celsius” using the header support. The position of the text can be customized by using the Position property.

<gauge:SfCircularGauge.Headers><gauge:Header Text="Inside" TextSize="22" ForegroundColor="#929292" Position="0.5,0.325" /><gauge:Header Text="Temp." TextSize="22" ForegroundColor="#929292" Position="0.46,0.63" /><gauge:Header Text="C" ForegroundColor="#929292" TextSize="22"  Position="0.59, 0.63"/><gauge:Header Text="o" ForegroundColor="#929292" TextSize="14" Position="0.562,0.62"/></gauge:SfCircularGauge.Headers>

 

Annotation

Annotations contain a collection of annotation elements, and you can add any number of annotations inside the circular gauge. Annotations display metadata about a circular gauge at a specific point of interest in the plotting area. They provide options to add any view element, image, or text on the gauge.

To display the current pointer value in the temperature monitor, use annotation support to display the text value over the circular gauge. You can simply bind the current temperature point value to annotation label text.   

The position of annotations can be customized using the Offset and Angle properties. The Offset property is used to move the annotation from the center to the required distance, whereas the Angle property places the annotation with respective angle direction.

<gauge:SfCircularGauge.Annotations><gauge:GaugeAnnotation Offset="0.7" Angle="90" ><gauge:GaugeAnnotation.View><Label HorizontalTextAlignment="Center"  VerticalTextAlignment="Center" WidthRequest="130"  Text="{Binding Value, Source={Reference pointer}}"  BackgroundColor="#bebfb7" FontSize="22" FontAttributes="Bold" TextColor="Black" /></gauge:GaugeAnnotation.View></gauge:GaugeAnnotation></gauge:SfCircularGauge.Annotations>

 

Conclusion 

Syncfusion’s circular gauge control for Xamarin.Forms has been designed with flexible UI customization to adapt to your app easily. It includes developer-friendly APIs to increase developers’ productivity. This control is also available for Xamarin.Android and Xamarin.iOS platforms.

Feel free to visit the circular gauge’s feature tourand documentation to learn more about its features and APIs. Also be sure to check out the complete sample, which is readily runnable, and see just how easy it is to create and configure the circular gauge.

If you have any questions or need clarification, please let us know in the comments section. You can also contact us through our support forum or Direct-Trac. We are happy to assist you!

Top 8 JavaScript E-books for Coding the Future

$
0
0

For years now, JavaScript has dominated web development. And Syncfusion’s Succinctly series has been helping developers keep up with the latest trends and frameworks. In this blog post, you’ll find the top eight Succinctly e-books relating to JavaScript. Whether you’re new to this language and need somewhere to start, or you’re a veteran JavaScript writer, but perhaps aren’t as smooth as you’d like to be with one of these particular frameworks, these Succinctly books will help you on your way to successful web development.

 

 

Angular 2 Succinctly

by Joseph D. Booth

 

In Angular 2 Succinctly, learn how to set up templates, compose components from those templates, and tie them all together with modules to deliver a cohesive web app.

 

Download Here

 

Ionic Succinctly

By Ed Freitas

 

Create cross-platform mobile and Progressive Web apps with this open-source SDK, built on Angular and written in TypeScript.

 

Download Here

 

JavaScript Succinctly

By Cody Lindley

 

Solidify your understanding of this language with the concise examination of JS objects and supporting nuances. 

 

Download Here

 

TypeScript Succinctly

By Steve Fenton

 

Learn how TypeScript provides optional static typing and classes to JavaScript development.

 

Download Here

 

Gulp Succinctly

By Kris van der Mast

 

Favor code over configuration with the JavaScript task runner Gulp.

Download Here

 

jQuery Succinctly

By Cody Lindley

 

Examine jQuery code examples and concepts to become a seasoned jQuery developer.

 

Download Here

 

React.JS Succinctly

By Samer Buna

 

Take a walkthrough of the basics of declarative user interfaces, React components, working with user input, and more.

 

Download Here

 

ECMAScript Succinctly

By Matthew Duffield

 

Learn to use ECMAScript’s new functionality and features to create advanced applications.



Download Here

 

All titles in the Succinctly series are free to download for everyone and always will be. If you found one of these JavaScript-related Succinctly e-books useful, let us and future readers know in the comments below.

Viewing all 473 articles
Browse latest View live