Creating an Image Editor Using CamanJS: Layers, Blend Modes, and Events

In the previous tutorial, you learned how to create an image editor using CamanJS which can apply basic filters like contrast, brightness, and noise to an image. CamanJS also has some other built-in filters like Nostalgia, Pinhole, Sunrise, etc., which we applied directly to the image.

In this tutorial, we will cover some more advanced features of the library like Layers, Blend Modes, and Events.

Layers in CamanJS

In the first tutorial, we only worked with a single layer which contained our image. All the filters that we applied only manipulated that main layer. CamanJS allows you to create multiple layers to enable you to edit your images in a more sophisticated manner. You can create nested layers, but they will always be applied on their parent layer like a stack.

Whenever you create a new layer and apply it on the parent layer, the default blend mode used will be normal. You can create a new layer on the canvas using the newLayer() method. When you create a new layer, you can also pass a callback function which will be useful if you intend to manipulate layer.

This function can be used for a lot of tasks like setting the blend mode for the new layer using the setBlendingMode() method. Similarly, you can control the opacity of the new layer using the opacity() method.

Any new layer that you create can be filled with a solid color using the fillColor() method. You can also copy the contents of the parent layer to the new layer using the copyParent() method. All the filters that we learned about in the previous tutorial can also be applied on the new layer that we are creating. For example, you can increase the brightness of the newly created layer by using this.filter.brightness(10).

Instead of copying the parent or filling the layer with a solid color, you also have the option to load any other image in the layer and overlay it on the parent. Just like the main image, you will be able to apply different filters to the overlaid image as well.

In the following code snippet, we have attached a click event handler to three buttons which will fill the new layer with a solid color, the parent layer, and an overlay image respectively.

Blend Modes in CamanJS

In the previous section, we kept the opacity of any new layer that we added to the canvas below 100. This was done because the new layer would otherwise hide the old layer completely. When you place one layer over another, CamanJS allows you to specify a blend mode which determines the final outcome after the placement. The blend mode is set to normal by default. 

This means that any new layer that you add on the canvas will make the layer below it invisible. The library has ten blend modes in total. These are normal, multiply, screen, overlay, difference, addition, exclusion, softLight, exclusion, and darken.

As I mentioned earlier, the normal blend mode sets the final color to be equal to the color of the new layer. The multiply blend mode determines the final color of a pixel by multiplying the individual channels together and then dividing the result by 255. The difference and addition blend modes work in a similar manner, but they subtract and add the channels. 

The darken blend mode sets the final color of a pixel to be equal to the lowest value of individual color channels. The lighten blend mode sets the final color of a pixel to be equal to the highest value of individual color channels. The exclusion blend mode is somewhat similar to difference, but it sets the contrast to a lower value. In the case of the screen blend mode, the final color is obtained by inverting the colors of each layer, multiplying them, and then again inverting the result. 

The overlay blend mode acts like multiply if the bottom color is darker, and it acts like screen if the bottom color is lighter.

If you want the colors in different layers to interact in a different manner, CamanJS also lets you define your own blend modes. We will cover this in the next tutorial of the series.

Here is the JavaScript code to apply different blend modes on an image:

In the above code snippet, we get the Hex color value from an input field. This color is then applied on the new layer. You can write the code to apply other blend modes in a similar manner.

Try to specify a color of your choice in the input field, and then apply any of the blend modes by clicking on the respective button. I have applied the blend modes on a solid color in the example, but you can also apply them on an overlaid image from the previous section.

Events in CamanJS

If you uploaded any large image in either the demo of the first tutorial or the second tutorial, you might have noticed that the result of any applied filter or blend mode became evident after a long time. 

Large images have a lot of pixels, and calculating the final value of different channels for each pixel after applying a specific blend mode can be very time-consuming. For example, when applying the multiply blend mode on an image with dimensions 1920*1080, the device will have to perform multiplication and division over 6 million times.

In such cases, you can use events to give users some indication about the progress of a filter or blend mode. CamanJS has five different events which can be used to execute specific callback functions at different stages. These five events are processStart, processComplete, renderFinished, blockStarted, and blockFinished.

The processStart and processComplete events are triggered after a single filter starts or finishes its rendering process. When all the filters that you specified have been applied on an image, the library fires the renderFinished event. 

CamanJS divides large images into blocks before starting to manipulate them. The blockStarted and blockFinished events are fired after individual blocks of the image have been processed by the library.

In our example, we will only be using the processStart and renderFinished events to inform users about the progress of our image editing operation.

With the processStart and processFinish events, you get access to the name of the process currently operating on the image. The blockStarted and blockFinished events, on the other hand, give you access to information like the total number of blocks, the current block being processed, and the number of finished blocks.

Try clicking on any button in the demo below, and you will see the name of the process currently manipulating the image in the area below the canvas.

Final Thoughts

The first tutorial of the series showed you how to create a basic image editor with built-in filters from the CamanJS library. This tutorial showed you how to work with more than one layer and apply different filters and blend modes to each layer individually.

Since the image editing process can take a while for large images, we also learned how to indicate to users that the image editor is actually processing the image and not sitting idle.

In the next and final tutorial of the series, you will learn how to create your own blend modes and filters in CamanJS. If you have any questions related to this tutorial, feel free to let me know in the comments.


Source: Nettuts Web Development

The Secret Sauce for Creating an Amazing Product

This article was originally published on Monday.com. Thank you for supporting the partners who make SitePoint possible.

9 out of 10 startups fail. This apocryphal statistic is generally accepted as fact because the simple truth is, building a successful business is hard.

There are many obvious factors that have contributed to monday.com’s success as a product and business—hard work, luck, determination—but much of where we’ve arrived today is thanks to the less obvious lessons that our founders learned the hard way.

When launching a new business and looking for a product/market fit, many people ask questions like:

  • Do we solve a problem?
  • Do people understand our solution?
  • Are they able to implement our solution?
  • Do we add value?

This is a good start, but it’s not close to enough. In this post, we’ll share some of our co-founders Roy Man and Eran Zinman’s hard-earned insights on how they built a strong business. They’ve both been developing and building products since they were kids and have a lot of successes and failures under their belt.

Beautiful design and excellent code don’t matter (at first)

Roy: “I built two startups that succeeded in some aspects but failed to turn into viable businesses. They were really good looking products with an excellent code base, but that didn’t help. It also didn’t help that people who saw these products were amazed and loved them—something didn’t work and I had no idea what.

So I went to my good friend and mentor Avishai Abrahami, the CEO of Wix, and told him that he had to show me how to get it right. So I joined Wix in 2010 when they were a startup of 80 people.”

Eran: “After I got my degree, I started my own company building a search engine for user reviews, where you could get an aggregated view of all reviews. I rented 15 computers that crawled the web 24/7 and put them on the second floor of my mom’s house. I got a call from our Internet provider who were like, ‘Uh, what are you doing?’

“I made every mistake you can make as an entrepreneur. I thought that you have to build an excellent product before you raise money. We kept improving it and perfecting it for a whole year while I burned through my life’s savings. Finally, my account was frozen, and I had to call it quits.

Working with your intuition is always wrong. You look at other companies and success stories and try to reverse-engineer them. It’s never like that. I thought, ‘I’m going to create the next Google. When I launch, it’s going to be perfect.’ I had no idea that I should have shared it with users and gotten feedback really early on.”

Roy: “When I joined Wix, I couldn’t believe how bad their codebase was. Their product design was pretty childlike, and the UI was horrible. Nothing acted like anything you’d expect. The Head of Product back then was proud of the fact that their ‘color picker’ was designed by a color-blind person.

Continue reading %The Secret Sauce for Creating an Amazing Product%


Source: Sitepoint

Angular 2 Authentication: Protecting Private Content

In this article, we’ll add authentication to our Angular application and learn how we can protect sections from our application from unauthorized access.

This article is part 5 of the SitePoint Angular 2+ Tutorial on how to create a CRUD App with the Angular CLI.

  1. Part 0 — The Ultimate Angular CLI Reference Guide
  2. Part 1 — Getting our first version of the Todo application up and running
  3. Part 2 — Creating separate components to display a list of todos and a single todo
  4. Part 3 — Update the Todo service to communicate with a REST API
  5. Part 4 — Use Angular router to resolve data
  6. Part 5 — Add authentication to protect private content

In part 1 we learned how to get our Todo application up and running and deploy it to GitHub pages. This worked just fine but, unfortunately, the whole app was crammed into a single component.

In part 2 we examined a more modular component architecture and learned how to break this single component into a structured tree of smaller components that are easier to understand, reuse and maintain.

In part 3 we updated our application to communicate with a REST API backend using RxJS and Angular’s HTTP service.

In part 4, we introduced Angular Router and learned how the router updates our application when the browser URL changes and how we can use the router to resolve data from our backend API.

Don’t worry! You don’t need to have followed part 1, 2, 3 or 4 of this tutorial, for five to make sense. You can simply grab a copy of our repo, check out the code from part 4, and use that as a starting point. This is explained in more detail below.

Up and Running

Make sure you have the latest version of the Angular CLI installed. If you don’t, you can install it with the following command:

npm install -g @angular/cli@latest

If you need to remove a previous version of the Angular CLI, you can run this:

npm uninstall -g @angular/cli angular-cli
npm cache clean
npm install -g @angular/cli@latest

After that, you’ll need a copy of the code from part 4. This is available at https://github.com/sitepoint-editors/angular-todo-app. Each article in this series has a corresponding tag in the repository so you can switch back and forth between the different states of the application.

The code that we ended with in part 4 and that we start with in this article is tagged as part-4. The code that we end this article with is tagged as part-5.

You can think of tags like an alias to a specific commit id. You can switch between them using git checkout. You can read more on that here.

So, to get up and running (with the latest version of the Angular CLI installed) we would do this:

git clone git@github.com:sitepoint-editors/angular-todo-app.git
cd angular-todo-app
git checkout part-4
npm install
ng serve

Then visit http://localhost:4200/. If all’s well, you should see the working Todo app.

Plan of Attack

In this article, we will:

  • set up a backend to authenticate against
  • add a sign-in method to our existing ApiService
  • set up an authentication service to handle authentication logic
  • set up a session service to store session data
  • create a SignInComponent to display a sign-in form
  • set up a route guard to protect parts of our application from unauthorized access.

By the end of this article, you’ll understand:

  • the difference between cookies and tokens
  • how to create an AuthService to implement authentication logic
  • how to create a SessionService to store session data
  • how to create a sign-in form using an Angular reactive form
  • how to create a route guard to prevent unauthorized access to parts of your application
  • how to send a user’s token as an Authorization Header in an HTTP request to your API
  • why you should never send your user’s token to a third party.

Our application will look like this:

Part 5 Authentication Demo

So, let’s get started!

Authentication Strategy

Server-side web applications typically handle user sessions on the server. They store session details on the server and send the session ID to the browser via a cookie. The browser stores the cookie and automatically sends it to the server with every request. The server then grabs the session ID from the cookie and looks up the corresponding session details from its internal storage (memory, database, etc). The session details remain on the server and are not available in the client.

In contrast, client-side web applications, such as Angular applications, typically manage user sessions in the client. The session data is stored in the client and sent to server when needed. A standardized way to store sessions in the client are JSON Web Tokens, also called JWT tokens. If you’re unfamiliar with how tokens work, check out this simple metaphor to easily understand and remember how token-based authentication works and you’ll never forget again.

If you want to get a deeper understanding of cookies and tokens, make sure to check out Philippe De Ryck’s talk on Cookies versus tokens: a paradoxial choice.

Due to the popularity of JSON Web Tokens in today’s ecosystem, we’ll use a JWT-based authentication strategy.

Setting Up the Backend

Before we can add authentication to our Angular application, we need a back end to authenticate against.

In the previous parts of this series, we use json-server to serve back end data based on the db.json file in the root of our project.

Luckily, json-server can also be loaded as a node module, allowing us to add custom request handlers.

Let’s start by installing the body-parser npm module, which we’ll need to parse the JSON in our HTTP requests:

$ npm install --save body-parser

Next, we create a new file json-server.js in the root of our project:

const jsonServer = require('json-server');
const server = jsonServer.create();
const router = jsonServer.router('db.json');
const middlewares = jsonServer.defaults();
const bodyParser = require('body-parser');

// Sample JWT token for demo purposes
const jwtToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiU2l0ZVBvaW50IFJ' +
  'lYWRlciJ9.sS4aPcmnYfm3PQlTtH14az9CGjWkjnsDyG_1ats4yYg';

// Use default middlewares (CORS, static, etc)
server.use(middlewares);

// Make sure JSON bodies are parsed correctly
server.use(bodyParser.json());

// Handle sign-in requests
server.post('/sign-in', (req, res) => {
  const username = req.body.username;
  const password = req.body.password;
  if(username === 'demo' && password === 'demo') {
    res.json({
      name: 'SitePoint Reader',
      token: jwtToken
    });
  }
  res.send(422, 'Invalid username and password');
});

// Protect other routes
server.use((req, res, next) => {
  if (isAuthorized(req)) {
    console.log('Access granted');
    next();
  } else {
    console.log('Access denied, invalid JWT');
    res.sendStatus(401);
  }
});

// API routes
server.use(router);

// Start server
server.listen(3000, () => {
  console.log('JSON Server is running');
});

// Check whether request is allowed
function isAuthorized(req) {
  let bearer = req.get('Authorization');
  if (bearer === 'Bearer ' + jwtToken) {
    return true;
  }
  return false;
}

This article is not meant to be a tutorial on json-server, but let’s quickly have a look at what’s happening.

First we import all json-server machinery:

const jsonServer = require('json-server');
const server = jsonServer.create();
const router = jsonServer.router('db.json');
const middlewares = jsonServer.defaults();
const bodyParser = require('body-parser');

In a real-world application, we would dynamically generate a JWT token when a user authenticates, but for the purpose of this demo, we define a JWT token statically:

// Sample JWT token for demo purposes
const jwtToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiU2l0ZVBvaW50IFJ' +
  'lYWRlciJ9.sS4aPcmnYfm3PQlTtH14az9CGjWkjnsDyG_1ats4yYg';

Next, we configure json-server to run its own default middlewares:

// Use default middlewares (CORS, static, etc)
server.use(middlewares);

and to parse incoming JSON requests properly:

// Make sure JSON bodies are parsed correctly
server.use(bodyParser.json());

Json-server’s default middlewares are request handler functions that deal with static files, CORS, etc. For more detailed information, check out the documentation.

We then define a request handler for sign-in requests:

// Handle sign-in requests
server.post('/sign-in', (req, res) => {
  const username = req.body.username;
  const password = req.body.password;
  if(username === 'demo' && password === 'demo') {
    res.json({
      name: 'SitePoint Reader',
      token: jwtToken
    });
  }
  res.send(422, 'Invalid username and password');
});

We tell json-server to listen for HTTP POST requests on /sign-in. If the request contains a username field with a value of demo and password field with a value of demo, we return an object with the JWT token. If not, we send an HTTP 422 response to indicate that the username and password are invalid.

In addition, we also tell json-server to authorize all other requests:

// Protect other routes
server.use((req, res, next) => {
  if (isAuthorized(req)) {
    console.log('Access granted');
    next();
  } else {
    console.log('Access denied, invalid JWT');
    res.sendStatus(401);
  }
});

// Check whether request is allowed
function isAuthorized(req) {
  let bearer = req.get('Authorization');
  if (bearer === 'Bearer ' + jwtToken) {
    return true;
  }
  return false;
}

If the client’s HTTP request contains an Authorization header with the JWT token, we grant access. If not, we deny access and send an HTTP 401 response.

Finally, we tell json-server to load the API routes from db.json and start the server:

// API routes
server.use(router);

// Start server
server.listen(3000, () => {
  console.log('JSON Server is running');
});

To start our new back end, we run:

$ node json-server.js

For our convenience, let’s update the json-server script in package.json:

"json-server": "node json-server.js"

Now we can run:

$ npm run json-server

> todo-app@0.0.0 json-server /Users/jvandemo/Projects/sitepoint-editors/angular-todo-app
> node json-server.js

JSON Server is running

And voila, we have our own API server with authentication running.

Time to dig into the Angular side.

Adding Authentication Logic to our API Service

Now that we have an API endpoint to authenticate against, let’s add a new method to our ApiService to perform an authentication request:

@Injectable()
export class ApiService {

  constructor(
    private http: Http
  ) {
  }

  public signIn(username: string, password: string) {
    return this.http
      .post(API_URL + '/sign-in', {
        username,
        password
      })
      .map(response => response.json())
      .catch(this.handleError);
  }

  // ...

}

When called, the signIn() method performs an HTTP POST request to our new /sign-in API endpoint, including the username and password in the request body.

If you’re not familiar with Angular’s built-in HTTP service, make sure to read Part 3 — Update the Todo service to communicate with a REST API.

Continue reading %Angular 2 Authentication: Protecting Private Content%


Source: Sitepoint

Authentication with Angular and Auth0

This article was originally published on the Auth0.com blog, and is republished here with permission.

In this tutorial, we’re going to build an Angular application and add login functionality using token-based authentication with Auth0.

You can check out the completed code example from our GitHub repo.

The Angular Ecosystem

AngularJS 1.x was highly regarded as a robust framework for building single-page applications (SPAs). It did a lot of things well, fell short on some, but overall allowed developers to quickly build powerful applications.

While AngularJS (1.x) is a framework, Angular is an entire platform for building modern applications. Alongside the core Angular library, the platform ships with a powerful command line interface (CLI) called Angular CLI that allows developers to easily scaffold their applications as well as control the build system. Angular Platform Server brings server-side rendering to Angular applications. Angular Material is the official implementation of Google’s Material Design, which allows developers to build beautiful applications with ease.

Our App: Daily Deals

Daily Deals App

The app we’re building today is called Daily Deals. The Daily Deals app displays a list of deals and discounts on various products. We’ll have a list of publicly available deals that anyone can see and a list of private deals available only to registered members. The private deals are exclusive to registered members, and should hopefully be better.

Serving the Daily Deals

We’ll have to get our daily deals from somewhere. Let’s build a very simple Node.js back end to serve the deals. We’ll have a publicly accessible route serving public deals and a protected route that can only be called by authenticated users. For now, we’ll make both of the routes public and worry about the authentication piece later. Take a look at our implementation below:

'use strict';
// Load dependencies
const express = require('express');
const app = express();
const cors = require('cors');
const bodyParser = require('body-parser');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());

// Public route
app.get('/api/deals/public', (req, res)=>{
  let deals = [
    // Array of public deals here
  ];
  res.json(deals);
})

// Private route
app.get('/api/deals/private', (req,res)=>{
  let deals = [
    // Array of Private Deals here
  ];
  res.json(deals);
})

app.listen(3001);
console.log('Serving deals on localhost:3001');

Both our server and the Angular app we are building will require Node.js and NPM, so be sure to have those installed before continuing. Check out the GitHub repo to get our list of daily deals or create your own. The model for each deal will be as follows:

 {
    id: 1234,
    name: 'Name of Product',
    description: 'Description of Product',
    originalPrice: 19.99, // Original price of product
    salePrice: 9.99 // Sale price of product
}

When you’re happy with the public and private deals, launch the server by running node server and navigate to both localhost:3001/api/deals/public and localhost:3001/api/deals/private to make sure you can see the list of deals you added. Next, let’s set up our Angular front end.

Angular Front End Setup

One of the best ways to start building a new Angular app is with the official Angular CLI. The CLI can take care of scaffolding the initial app, adding additional components, takes care of the build system and much more. In this tutorial, we’ll scaffold our initial app with the CLI.

If you don’t already have it installed, run:

npm install @angular/cli -g

This installs the Angular CLI globally. We’ll interact with the CLI using the ng command. To create a new application, choose a directory and run:

ng new ng2auth --routing --skip-tests

This will create a new Angular application with routing and no initial test files for the root component. The app will be created in its own folder in the current directory, and the CLI will download all of the required npm packages and basically set everything up for us.

Once ng new is finished, enter the new directory and run the ng serve command and the Webpack based build system will take care of compiling our app from TypeScript to JavaScript and will serve our app on localhost:4200. The ng serve command will also kick off a live sync process, so any time we make a change our app will automatically recompile.

Let’s head over the localhost:4200 for now to make sure that everything is working as expected so far. If you see a message saying “app works!”, you’re golden. Next, let’s examine how our Angular app is scaffolded.

The ng new command scaffolded our Angular app and added a lot of files. Many of these we can ignore for now like the e2e folder, which would contain our end-to-end tests. Open up the src directory. In the src directory, we can see some familiar files like index.html, styles.css, and so on. Open up the app directory.

The app directory contains the bulk of our application. By default, we’re presented with the following files:

  • app.component.css – Holds the CSS styles for our root component
  • app.component.html – Holds the HTML view for our root component
  • app.component.ts – Holds the TypeScript logic for our root component class
  • app.module.ts – Defines our global app dependencies
  • app-routing.module.ts – Defines our app’s routes.

Each Angular component we write will have at a minimum the *.component.ts file, the others are optional. Our application is going to have three components. The main or root component, a component to display the public deals, and a component to display private deals. For our root component, we’ll inline the template and styles. Let’s make the following edits and run the following CLI commands:

  • Delete app.component.css and app.component.html files. We’ll define all we need for our root component in the app.component.ts file.
  • Create a public-deals component by running ng g c public-deals --no-spec. This component will take care of getting and displaying the public deals data.
  • Create a private-deals component by running ng g c private-deals --no-spec. This component will take care of getting and displaying the private deals data.
  • Create a callback.component.ts file by running ng g c callback --it --is --flat --no-spec.
  • Create a deal file by running ng g class deal --no-spec. This file will hold our deal class, which will let Angular know the structure of a deal.
  • Create a deal.service.ts file by running ng g s deal --no-spec. Here we’ll add the functionality to get and retrieve the deal data from our API.

Note: g is a shortcut for generate, and c and s are shortcuts for component and service, respectively. Therefore, ng g c is equivalent to ng generate component. The --no-spec flag indicates that *.spec.ts files should not be generated. The --it and --is flags stand for “inline template” and “inline styles” and --flat indicates that a containing folder should not be created.

Adding HTTP Client Module

We’re going to be making HTTP requests to our API in our Angular app. To do so, we need to add the correct module to our app.module.ts file. Let’s do so now by importing the HttpClientModule and adding it to our @NgModule’s imports array like so:

// app.module.ts
...
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Adding Bootstrap CSS

We’re going to use Bootstrap to style our application, so let’s include the CSS in the <head> of our index.html file like so:

<!-- src/index.html -->
...
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
...

Building the Root Component

Every Angular application must have a root component. We can name it whatever we want, but the important thing is that we have one. In our application, the app.component.ts file will be our root component. Let’s take a look at our implementation of this component.

// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div class="container">
      <nav class="navbar navbar-default">
        <div class="navbar-header">
          <a class="navbar-brand" routerLink="/dashboard">{{ title }}</a>
        </div>
        <ul class="nav navbar-nav">
          <li>
            <a routerLink="/deals" routerLinkActive="active">Deals</a>
          </li>
          <li>
            <a routerLink="/special" routerLinkActive="active">Private Deals</a>
          </li>
        </ul>
        <ul class="nav navbar-nav navbar-right">
          <li>
            <a>Log In</a>
          </li>
          <li>
            <a>Log Out</a>
          </li>
        </ul>
      </nav>
      <div class="col-sm-12">
        <router-outlet></router-outlet>
      </div>
    </div>
  `,
  styles: [
    `.navbar-right { margin-right: 0px !important}`
  ]
})
export class AppComponent {
  title = 'Daily Deals';

  constructor() {}
}

We’ve created our root component. We added an inline template and some inline styles. We haven’t added all the functionality yet, so every user will be able to see all the links and the login and logout buttons. We’ll wait to implement those a little bit. We’re also displaying the <router-outlet> element. This is where our routed components will show.

Routing

Since we initialized our app with the --routing flag, the architecture for routing is already set up for us. Let’s update it so that our Deals component shows by default. We’ll also set up all the routes necessary for our app.

Open the app-routing.module.ts file and add the following:

// app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CallbackComponent } from './callback.component';
import { PublicDealsComponent } from './public-deals/public-deals.component';
import { PrivateDealsComponent } from './private-deals/private-deals.component';

const routes: Routes = [
  {
    path: '',
    redirectTo: 'deals',
    pathMatch: 'full'
  },
  {
    path: 'deals',
    component: PublicDealsComponent
  },
  {
    path: 'special',
    component: PrivateDealsComponent
  },
  {
    path: 'callback',
    component: CallbackComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

We can just navigate to localhost:4200 in the browser and see our app displayed. We won’t see much yet, just the top navbar and a message saying that the deals component works.

The Deal Type

TypeScript allows us to define the structure or type of our objects. This serves a bunch of useful purposes. For one, if we define the structure of an object, we’ll be able to get all of the object’s data via IntelliSense. We can additionally test our components easier by knowing the data structure or type of object we are dealing with.

For our app, we’ll create one such type. In the deal.ts file, we’ll define a type of Deal. Let’s see how we’ll accomplish this.

// deal.ts
export class Deal {
  id: number;
  name: string;
  description: string;
  originalPrice: number;
  salePrice: number;
}

Now we can declare objects in our Angular application to be a type of deal. These objects will gain all of the properties and methods of the deal type. We’re only defining properties here; we won’t have any methods.

Continue reading %Authentication with Angular and Auth0%


Source: Sitepoint

Understanding Logical Properties And Values

In the past, CSS has tied itself to physical dimensions and directions, physically mapping the placement of elements to the left, right and top and bottom. We float an element left or right, we use the positioning offset properties top, left, bottom and right. We set margins, padding, and borders as margin-top and padding-left. These physical properties and values make sense if you are working in a horizontal, top to bottom, left to right writing mode and direction.
Source: Smashing Magazine

How to Build Push Notifications for Web Applications

This article was originally published on Sencha. Thank you for supporting the partners who make SitePoint possible.

Progressive Web Applications have become a viable alternative to native applications: they can be installed, used to work offline, and have access to the device hardware. In this article, I’ll show you how to make your existing web applications even better than before by adding native-like notifications. I’ll explain the concept of Web Push Notifications and show you how to add them to your existing web apps. Last, I’ll cover the state of specifications and browser support.

Web Push Notifications Protocol

The Web Push Notifications protocol is relatively new. It gives web applications the ability to act as native applications and receive messages pushed to them from a server at any time even when the web app is not active or not currently loaded in a browser. This lets you engage users with urgent and relevant notifications when they are not using your application and motivate them to return to the application.

Web Push Message

It makes clear the commercial value of implementing Web Push Notifications in your web apps. It increases user engagement. The overall value of your application increases too, because push notifications make your application more useful for your users. This improves the usability of web applications and moves us closer to developing a single web application for all platforms instead of having to develop a native application for every platform.

Web Push vs Web Sockets

Before going into the details of the technology, I would like to talk a bit about the differences between Web Push and Web Sockets. First, here is what they have in common. Web Push and Web Sockets are designed to implement real-time communication between the web application and application server, and to send real-time data and updates from the application server to your web application.

Here are the differences:

  • Web Sockets can only be used when a web page is loaded and active. But the opposite is true of Web Push Notifications which can be used at any time, including when the application is active, inactive, or not loaded, and when the browser is not active or even closed.
  • Data sent using Web Push must be encrypted, and there is a size limit per message (it must not be larger than 4Kb). There’s also a count limit for the number of messages you are allowed to send (the exact limit value depends on the browser). Some browsers (for example Chrome) may also require that a notification be displayed to the user every time a message is received. You don’t have any of these limitations when you use Web Sockets: you can send any number of unencrypted messages of any size and handle them as you want; and you may display a notification or silently update the data in your application or even do nothing at all.
  • The general rule is to use Web Sockets for sending ordinary data updates to your web app when a user is interacting with the application. Use Web Push Notifications for sending urgent and important messages to a user that have to be received immediately, whether or not the user is working with your application at that moment.

Technical Concepts

Let’s move to the technical details of the technology. I would like to explain the details using a game with special rules, players, and rounds. I’ll start by describing the players of the game. There are 5 players involved in this game called Web Push Notifications:

  • Web Application
  • Service Worker
  • Browser
  • Application Server
  • Push Server

Push Server is a service that is implemented by the browser vendor; it is a communication bridge between your application server and a browser. It is responsible for delivering messages from your application server to the browser.

Using a Game to Demonstrate Web Push Notifications

Using a game, I’ll demonstrate how you can add web push notifications to your apps. The rules of this game are defined by several specifications provided by the World Wide Web Consortium and the Internet Engineering Task Force:

  • Communications between the Browser and the web application or service worker associated with this application are described in the Push API specification.

  • Displaying different types of Notifications as well as Notification handling are described in the Notifications API specification.

  • Communications between the Application Server and the Push Server are defined in the Web Push Protocol specification.

  • There are also additional specifications describing push message encryption and application server identification that let your application server prove that it is allowed to send messages to your user.

Push API

Game Rounds

I have split the game into four rounds and will explain the concept and target of every round. Then, I’ll show you how you can implement every round in your application.

Round 1: Service Worker Registration

Web Push Notifications require Service Workers to handle push messages, so the first round will be to register your service worker. Only your web application and the browser are involved in this round. And this round occurs at the page load.

The web application sends a request to a browser to register a Service Worker and the browser replies with the ServiceWorkerRegistration object if the Service Worker was registered successfully.

Register

To implement this round, you need to add the following code to your web application:

if ('serviceWorker' in navigator) {

  if ('PushManager' in window) {

    navigator.serviceWorker.register('ServiceWorker.js').then(function(registration) {

      //state initializing

    })

    .catch(function() {

      //error handling

    });

  } else {

    //error handling

  }

} else {

  //error handling

}

First, we need to check if the browser supports Service Workers. Then, we need to check if the browser supports web push notifications. As browser support is growing, it’s always a good idea to add both checks.

If both are supported, we register our service worker. For this step, we call the navigator.serviceWorker.register() method and pass the path to our Service Worker file as a parameter. After this step, the browser will download this file and run it in a service worker environment. The Service Worker file is a standard JavaScript file, but the browser will “give it access” to the service worker APIs, including push. If everything ran correctly and there were no errors, the promise returned by register() will resolve. If there are errors of any kind, the promise is rejected, and we need to handle this case as well as the case when the browser doesn’t support Service Workers. When register() does resolve, it returns a ServiceWorkerRegistration object that will be used in the next round.

Round 2: Subscription

The second round handles the subscription for Web Push Notifications. This is when you ask the user if he wants to receive Web Push Notifications from your application, and if he agrees, you subscribe him. This round involves more players – Web Application, Browser, Application Server and Push Server and more communications.

This round should be played when a user is ready to subscribe. You should ask him to subscribe only when you are sure that it is relevant and meaningful for him, because you will only have one chance to ask. If the user blocks the request, then the browser will not permit you to ask this question again later. The only way to unblock an application is to change it in the browser settings. And as you can imagine, almost no user ever does this. So, you need to explain to the user what kind of Notifications he will receive and why. You may also offer to subscribe the user using a custom in-page message, and once the user clicks yes, then show him a system browser request.

What happens in this round? Your web application asks the browser to subscribe the user to receive Web Push Notifications. If the user agrees, the browser sends a request to the Push Server to generate a push subscription. The Push Server replies to the browser with a push subscription object that the browser forwards to your web application. As the last step, your web application sends this push subscription object to your application server via an Ajax call, for example. And your application server saves it to use in the next round.

Your web application is the main actor in this round, so this code should be added to your web app:

navigator.serviceWorker.ready.then(function(registration) {

  registration.pushManager.subscribe({

    userVisibleOnly: true,

    applicationServerKey: urlBase64ToUint8Array('...')

  })

  .then(function(subscription) {

    // The subscription was successful

    savePushSubscription(subscription);

  })

  .catch(function(e) {

    //error handling

  });

});

Once the service worker is ready, we can subscribe a user by calling the registration.pushManager.subscribe() method of the Service Worker registration object that we received in the previous round. The browser requests permission to show notifications to a user. If the user allows it, the promise will be resolved with a subscription object. The subscription object contains necessary information for sending a push notification to a user. Now, you will need to save this object on your application server. I won’t go deeper into this process – it could just be a standard Ajax call to the server, or you could send this object as a JSON or a string and then the server would need to save this object in a database. I will not show this code, because it highly depends on how your App Server is implemented. If the user denies permission or any other error occurs, then the promise will be rejected and you need to handle this issue.

Permission Request

If your web app doesn’t have permissions to show notifications at the time of calling subscribe(), the browser will request the permissions for you. But there is another option – you can request permissions manually by calling Notification.requestPermission method directly. This method will return a promise that resolves with the permission picked by the user. Possible values for this are granted, denied, or default.

Notification.requestPermission(function(result) {

  if (result!== 'granted') {

    //handle permissions deny

  }

});

Subscription Parameters

Let’s look at the parameter object passed into the subscribe method:

reg.pushManagerpushManager.subscribe({

  userVisibleOnly: true,

  applicationServerKey: new Uint8Array([...])

});
  • userVisibleOnly: If it’s set to true, it means that every push message will result in showing a Notification to the user. Silent push messages sent in the background, when the user isn’t notified, are not allowed in this case. Currently, Chrome only allows this option to be set to true because theoretically silent push could be used by a developer to do nasty things like setting up hidden geo tracking for example. Firefox supports a limited number of silent push messages. There might be changes in the specification regarding this rule.
  • applicationServerKey: It’s the public part of a public/private key pair identifying your application server. The browser will send this application server key to the push server, and it will be used by the push server to identify that the application subscribing a user is the same application that is messaging that user. I will explain the identification process in detail in the next round.

Subscription Object

Let’s look at the PushSubscription object that is returned by resolving the promise. This PushSubscription object is associated with the Service Worker that we registered in the previous round. This Push subscription describes the delivery bridge for push messages.

interface PushSubscription {

  readonly attribute endpoint;

  // &quot;https://{push_server_url}/{user_identifier}&quot;,

  function getKey();

  //auth - authentication secret

  //p256dh - key for encrypting messages

};

It contains two important parts:

Continue reading %How to Build Push Notifications for Web Applications%


Source: Sitepoint

Build Pixel Perfect Websites Without Dev-Design Conflict In Your Team

This article was created in partnership with CanvasFlip. Thank you for supporting the partners who make SitePoint possible.

Visual Inspector is a collaboration tool for getting feedback on your website. It helps stakeholders to visualize changes on live websites without coding and to collaborate effectively with developers.

Building a Pixel-Perfect Website Is Tough

As a developer, when you are building a web-based project with multiple stakeholders – designers, clients, delivery managers, etc, everyone likes to share their feedback on the fonts, colors, content copy, and almost on everything else.

At the end of the day, it is your responsibility to gather all the feedback from the stakeholders and implement their suggestions on your website.

But that’s much easier said than done.

Whereas there are many collaboration tools at the design stage, iterating on the post-development and pre-launch stages of website creation, is still a very cumbersome process.

First, to make suggestions on websites, one needs to “Inspect Element”, dig into native in-browser devtools, and apply coding skills (which most non-developer stakeholders like designers, customers, marketing folks, etc., don’t have or are not often even aware of).

Second, once these changes are made, working collaboratively over them with other stakeholders, e.g., discussing, making decisions, tracking these changes over email + Screenshot, etc., is an extremely painful process. Especially when collaborating with multiple stakeholders over multiple changes.

Traditional ways of getting collaborative feedback (Screenshot + Email) often result in delays in website development with a lot of wasted time and effort, not to mention the confusion this generates within a team.

Better Feedback Means Better Results

Thanks to the available technology, the cost of gathering feedback and making iterations has gone down multifold in the last few years. Iterations during web development are no different.

Let me introduce you to Visual Inspector, a simple in-browser editing tool, which lets you make temporary changes to live websites without any coding – more like a visual alternative to Chrome’s native DevTools.

Visual Inspector also allows you to share these changes remotely among stakeholders for faster design decisions.

Stakeholders can make these changes without coding, highlight them by adding comments right within the page, discuss issues by replying to the comments, or resolve issues/suggestions made by other team members.

Everyone in the team is always updated with real-time notifications over email/Slack or other integrations.

Collaboration among team members for pixel-perfect websites with Visual Inspector

Collaborate and get real-time feedback by sharing changes over a link

How to Get Started

Getting started with Visual Inspector is extremely easy and you should start with installing the extension.

Once installed, the extension will guide you in how you can make design changes and collaborate over them with stakeholders.

Continue reading %Build Pixel Perfect Websites Without Dev-Design Conflict In Your Team%


Source: Sitepoint

Building a Twitter Client with NodeJS and Angular

In this tutorial, we’re going to look at how to build a basic Twitter client with NodeJS, and an Angular application to display your home timeline of tweets. This is a rapid tour with things to consider while setting up your own Twitter client and Angular application.

First, we’re going to build a NodeJS server, which will handle communicating between the Twitter API and the Angular application. Then, we’ll build up the Angular application to display and interact with your Twitter timeline.

While you may be able to go through this tutorial without any prior NodeJS or Angular experience, I’ll assume some prior knowledge in the article.

Setting Up the Project

You’ll need a recent version of NodeJS set up on your machine. Then ensure you have the Angular CLI. The links provided give you a good place to start if you need help with either of those tasks.

The project source code can be found on GitHub. You can get it all running locally by either cloning it with Git or downloading the files from the repo’s GitHub archive.

git clone https://github.com/sitepoint-editors/twitter-angular-client

Once you have the files, from your terminal you’ll need to run npm install to get all of the dependencies installed. Then we can get to work!

Creating a Twitter Client in NodeJS

To access Twitter’s API, we need to register for a new “app”, which is essentially a way for Twitter to give us a set of credentials. These are unique for your application, so don’t share them publicly anywhere. You must, of course, have a Twitter account to access the data.

To start, go to https://apps.twitter.com/ and select Create New App. You can fill out the name, description, and website URL for your app. (You can use a fake URL for now. If you publish your app it should be your actual website.)

From there, you’ll see the new app page with your details. Go to the Keys and Access Tokens page, where you can see a button to Create my access token near the bottom. Click the button, and then you should see four values: Consumer Key (API Key), Consumer Secret (API Secret), Access Token, and Access Token Secret. We’ll use these in a moment, so be sure to keep this information handy.

Creating the Twitter Client in NodeJS

Now it’s time to dig into our NodeJS server, which will bridge the gap between Twitter’s API and the Angular app. In the project, you should see the server.js file, which you’ll need to open and tweak.

First, you’ll need to update the block that contains the credentials you received from the Twitter app earlier. You should copy those values into the block here. We’re using a Twitter package called Twit to help us connect to Twitter, though there are others available with various levels of functionality.

const client = new Twitter({
  consumer_key: 'CONSUMER_KEY',
  consumer_secret: 'CONSUMER_SECRET',
  access_token: 'ACCESS_TOKEN',
  access_token_secret: 'ACCESS_TOKEN_SECRET'
});

Now we should be able to connect to Twitter. We’re also using the popular ExpressJS to create and manage our server. Now that you have the credentials installed, you can run the server.

node server

Our next step is to make several routes that will handle the HTTP requests our Angular application will need to make to load the Twitter data. Our first route is to get the current user, and validate their credentials. The Access Token and Secret you provided are linked to your Twitter account, so you’ll be the authorized user in this case. When this route is called, it will call the Twitter account/verify_credentials endpoint and return an object containing your user data.

app.get('/api/user', (req, res) => {
  client.get('account/verify_credentials').then(user => {
    res.send(user)
  }).catch(error => {
    res.send(error);
  });
});

The next route we’ll create is to get your home timeline. It requests the statuses/home_timeline endpoint, and passes a few parameters to give us more of the data we need.

Due to rate limiting on the Twitter API, we’ve implemented a simple cache that will only request new data once a minute (which is the max rate before you receive errors). It basically keeps track of the last response and the time it was requested, only allowing new requests to Twitter to run after a minute. Rate limiting is a primary design consideration to have when building a Twitter app.

let cache = [];
let cacheAge = 0;

app.get('/api/home', (req, res) => {
  if (Date.now() - cacheAge > 60000) {
    cacheAge = Date.now();
    const params = { tweet_mode: 'extended', count: 200 };
    if (req.query.since) {
      params.since_id = req.query.since;
    }
    client
      .get(`statuses/home_timeline`, params)
      .then(timeline => {
        cache = timeline;
        res.send(timeline);
      })
      .catch(error => res.send(error));
  } else {
    res.send(cache);
  }
});

Finally, we create a set of routes to handle like/unlike and retweet/unretweet actions for a tweet. This will allow us not only to read data, but also take action. These will require that you’ve set the application Access Level to Read and write (in case you changed it in the Twitter app settings).

app.post('/api/favorite/:id', (req, res) => {
  const path = (req.body.state) ? 'create' : 'destroy';
  client
    .post(`favorites/${path}`, {id: req.params.id})
    .then(tweet => res.send(tweet))
    .catch(error => res.send(error));
});

app.post('/api/retweet/:id', (req, res) => {
  const path = (req.body.state) ? 'retweet' : 'unretweet';
  client
    .post(`statuses/retweet/${req.params.id}`)
    .then(tweet => res.send(tweet))
    .catch(error => res.send(error));
});

There are many Twitter APIs for engaging with Twitter data, but the fundamental rules remain the same. The only major issue here is we’ve hard-coded credentials to a single user, which you’d need in order to set up your own OAuth server (or use an existing one) to handle the authentication aspects, which you can learn more about on Twitter Authentication documentation.

Creating the Angular App

Now it’s time to turn our attention to the Angular application that uses the server we created. We’ll take a look at the key aspects of the application and how they work to create the final result. We’ve built this application using Clarity for the UI layer (it gives us many useful layout components), but otherwise everything is just Angular.

To run the Angular application, just run the following command and then open up http://localhost:4200:

ng serve

Inside of the application, we have a model at src/app/tweet.ts which contains the TypeScript interface that describes most of the properties of a tweet (some have been omitted). I believe it’s essential to describe your types properly for large-scale Angular applications as well as smaller ones, so this interface gives us the shape of a tweet.

Angular TwitterService

First, we’ll need a service that can make requests to our NodeJS server to get the latest tweets. In Angular, the HttpClient is the utility you use to make HTTP requests, so I’ve created an Angular service to encapsulate the logic for these calls. Open up src/app/twitter.service.ts and you’ll see the following code:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
import { Tweet } from './tweet';

export interface TwitterResponse {
  data: any;
  resp: any;
}

@Injectable()
export class TwitterService {

  constructor(private http: HttpClient) { }

  user() {
    return this.http.get<TwitterResponse>(`${environment.api}/user`);
  }

  home(since?: string) {
    return this.http.get<TwitterResponse>(`${environment.api}/home?since=${since}`);
  }

  action(property: 'favorite'|'retweet', id: string, state: boolean) {
    return this.http.post<TwitterResponse>(`${environment.api}/${property}/${id}`, {state});
  }
}

This is a fairly basic service, which has methods to build a request for each API that we’ll support. The user method will return the current user (which will always be you). The home method will return the latest 200 tweets in your home timeline (or how ever many appeared since the last tweet specified). Finally, the action property handles making either a favorite or retweet call, by sending a boolean state value to toggle the status.

This service is generic, and each of these methods returns an Observable. If you want to learn more about them, you can read about Functional Reactive with RXJS, but the way they’re used here is similar to how a promise works. We’ll see how to use them in a moment.

Using the Angular TwitterService to load user

We’ll use the TwitterService in a few places, starting with loading the AppComponent. We’ll use it to load the user details (which appears in the top corner), and to load the list of tweets for the home page. Open up src/app/app.component.ts and you should see the following code:

import { Component , OnInit } from '@angular/core';
import { TwitterService } from './twitter.service';
import { Tweet } from './tweet';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  providers: [TwitterService]
})
export class AppComponent implements OnInit {
  user;

  constructor(private twitter: TwitterService) {}

  ngOnInit() {
    this.twitter.user().subscribe(user => this.user = user.data);
  }
}

The AppComponent does one main thing using our TwitterService. The ngOnInit method fires as soon as the component has initialized, and requests the user data. Here we’re using the Observable returned by the TwitterService.user method, and when we use subscribe it will trigger the actual HTTP request to fire. Once it’s returned, the callback function stores the user property, which is used to display content in the navbar. You can see the user property bindings in the component template below, such as user.profile_image_url_https:

<clr-main-container>
  <clr-header class="header-4">
    <div class="branding">
      <a class="nav-link">
        <div class="title">Twangular</div>
      </a>
    </div>
    <div class="header-actions" *ngIf="user">
      <a class="nav-link">
        <span class="nav-text">
          <img [src]="user.profile_image_url_https" class="avatar" />
          @{{user.screen_name}}
        </span>
      </a>
    </div>
  </clr-header>
  <div class="content-container">
    <main class="content-area">
      <app-tweets></app-tweets>
    </main>
  </div>
</clr-main-container>

Also, the use of <app-tweets></app-tweets> will insert the TweetsComponent, which handles the actual loading and display of tweets, so let’s take a look at it now.

Continue reading %Building a Twitter Client with NodeJS and Angular%


Source: Sitepoint

New Short Course: Code a Front-End App With GraphQL and React

Final product image
What You’ll Be Creating

GraphQL is an emerging technology for creating APIs and sharing data between the server and front-end. In our new short course, Code a Front-End App With GraphQL and React, you’ll learn how to connect to a GraphQL endpoint from a React app. 

What You’ll Learn

In this quick, 50-minute course, Markus Mühlberger will show you how to configure the popular Apollo GraphQL client. This will let you seamlessly retrieve and integrate live server data into your app. 

You’ll learn how to structure your queries, access real-time data, perform mutations (updates to the server data), and handle errors. Along the way, you’ll build a great-looking trip planning map for the Finnish public transportation system!

Screenshot from the app youll be creating

Watch the Introduction

 

Take the Course

You can take our new course straight away with a subscription to Envato Elements. For a single low monthly fee, you get access not only to this course, but also to our growing library of over 1,000 video courses and industry-leading eBooks on Envato Tuts+. 

Plus you now get unlimited downloads from the huge Envato Elements library of 460,000+ creative assets. Create with unique fonts, photos, graphics and templates, and deliver better projects faster.


Source: Nettuts Web Development

Creating an Image Editor Using CamanJS: Applying Basic Filters

A while back, I wrote some tutorials which described how to apply different kinds of filters and blend modes to an image using just CSS. This could be very helpful in situations where you want to show the grayscale, blurred, or high-contrast version of the same image. Instead of creating four different images, you could just apply these effects to the original image using a few lines of CSS. 

Using CSS filters and blend modes works nicely in most cases. However, CSS doesn’t modify the pixels of the image itself. In other words, the filters and blend modes or any other effects are not permanent. 

If someone downloads an image with CSS filters applied to it, they will get the original image and not the modified version. This can be a major setback if you were planning on creating an image editor for your users.

If you want the image modifications to be permanent and allow the user to download the modified image, you can use HTML5 canvas. The canvas element allows you to do a lot of things, including drawing lines and shapes, writing text, and rendering animations. 

In this tutorial, we will focus on editing images loaded on the canvas. CSS3 already has built-in functionality to allow you to apply effects like contrast, brightness, and blurring directly. When working with HTML5 canvas, we will use a canvas manipulation library called CamanJS to edit the images. 

The library supports basic effects like brightness, contrast, and saturation out of the box. This will save time and allow us to create more sophisticated filters based on these basic ones.

CamanJS Basics

The name of this library is based on the fact that it is used for doing (ca)nvas (man)ipulation in JavaScript(JS). Before you can start using different features of the library, you will have to include it in your project. This can be done either by downloading the library and hosting it yourself or by linking directly to a CDN.

There are two ways to use the library. The first option is to use the data-caman attribute with your image elements. This attribute can accept a combination of different CamanJS filters as its value. For example, if you want to increase the brightness of an image by 20 and the contrast by 10, you can use the following HTML:

Similarly, you can apply other filters like saturation, exposure, noise, sepia, etc. Besides the basic filters, CamanJS also gives you access to some more sophisticated filters out of the box. These filters can be applied to an image in a similar manner. To apply the sunrise filter, you can simply use the following HTML:

Your second option for manipulating images is by calling Caman() with the id of the canvas where you have rendered the image and different filters that you want to apply to the rendered image.

In this series, we will be going the JavaScript way to create our image editor.

Implementing Upload and Download Functionality

You need to provide users with a way to upload the images they want to edit so that you can render them on the canvas for further manipulation. Once the users have made the changes, they should also be able to download the edited images. In this section, we will add these two functions to our image editor.

Let’s begin with the HTML needed to add the canvas and upload/download buttons:

Here is the code for implementing the basic image upload functionality:

We begin by creating some variables to store the name of the image file selected by the user and the context for our canvas. After that, we write the code to get the image file from the file input after its change event is fired. The files selected by a user are stored in a FileList, and we can get the first file from the list using .files[0]

Once we have the file, we use a FileReader object to read the contents of the file selected by the user. The onload event for the FileReader is triggered after the selected file has been read successfully. 

Inside the onload event handler for the FileReader object, we create an HTMLImageElement instance using the Image() constructor. The src attribute of the image is then set to the value of the result property of our FileReader

Once the image has loaded successfully, we set the width and height of our canvas to be equal to the width and height of the image selected by the user. After that, we draw the image on the canvas and remove the data-caman-id attribute from the canvas. 

The attribute is added automatically by CamanJS when setting up the canvas for editing an image. We need to remove it every time a user selects a new file in order to avoid any mixup between the old image file we were editing and the new file selected by the user.

Besides loading the image file in the canvas, we have also set the value of the fileName variable to be equal to the name of the file selected by the user. This will be useful when we are saving the edited image.

Users will now be able to upload different images in your image editor. Once they have edited the image, they would also like to download them. Let’s write some code that will allow users to save the edited image file.

We use the jQuery .on() method to execute a piece of code every time the click event is fired for the download button. This code removes the file extension from the name of the image file selected by the user and replaces it with the suffix -edited.jpg. This name is then passed to the download function along with a reference to the canvas where we rendered and edited the image. 

The download function creates a link and sets its download attribute to filename. The href attribute contains the data URI for the edited image. After setting the value of these two attributes, we programmatically fire the click event for our newly created link. This click starts the download of the edited image.

Applying Built-in Filters

As I mentioned in the beginning of the tutorial, CamanJS comes with basic built-in filters. So you can directly apply brightness, contrast, sepia, saturation, exposure, noise, sharpen, vibrance, and hue. Some filters like brightness and contrast can have a negative as well as a positive value. 

You can make the values as high or as low as you want, but a sensible choice would be to keep them between -100 and 100. For example, the image becomes white when you set the brightness to 100. So any value above 100 will be useless. Similarly, the image will become completely gray if you set the value of the contrast to -100.

Other filters like sepia, noise, sharpen, and blur will only accept a positive value. Keep in mind that the hue filter covers the full 360-degree circle, with values ranging from 0 to 100. The image will look exactly the same when you set the hue to 0 or 100.

Here is the HTML to add buttons for our image editor:

All the filters like brightness and contrast have been given increase and decrease buttons. However, the decrease button has been disabled for some filters like noise because they can’t have a meaningful negative value.

We will apply the respective filters based on the button clicked with the help of the following JavaScript.

For the increase and decrease buttons, the strength of the filter is based on how its effect scales. For example, the brightness and contrast are increased by 10, but the value of gamma is only increased by 0.1 after each click.

The following CodePen demo shows the CamanJS image editor we created in action.

Some filters might take some time before you see their final outcome. In such cases, users might think that the filter is not working. We will be using events to keep readers updated about the progress of a filter. All this will be discussed in the next tutorial.

Final Thoughts

The first tutorial was meant to teach you how to create an image editor with basic image upload and download functionality which users can use to edit images. We used basic filters like noise, contrast, and brightness as well as some more complicated effects like Vintage and Nostalgia, which are built into the library.

In the next tutorial, you will learn about more CamanJS features like layers, blend modes, and events. And in the meantime, don’t forget to review what we have available in the Envato Market for purchase, study, use, and review.


Source: Nettuts Web Development