Category: Web Applications

Setting up XDebug with Joomla

Introduction

Joomla! CMS is platform for website development which is using by quite a large number of people today. I have started using this few years back and contributed in many ways. Every time a development is going on, we came across situations where we need to look in to variables’s instance values. In some situations I just print that variable value. However in complex situation a help of a debugger is essential. There are several methods to debug Joomla during development process and most of them are mentioned in this reference article [1]. In this article I am describing one of those method in detail.

Pre-requisites

In my case I had the following setup;

  • Joomla CMS installed
  • Phpstrom on Windows
  • XAMPP which runs Apache and SQL

Now it’s time to start setting up.

Configuring XDebug on XAMPP

  • Download xdebug library suites for php version and OS (https://xdebug.org/download.php)
  • Put the library in php/ext folder
  • Add Xdebug configuration to the end of php.ini file
  • Add desired host and port
  • Restart XAMPP server and check phpinfo to verify xdebug section

Sample Xdebug configuration for php.ini file [2]. “zend_extension_ts” is the path to locate downloaded library.

[XDebug]
zend_extension = “c:\xampp\php\ext\php_xdebug-2.5.5-7.1-vc14.dll”
xdebug.remote_autostart = 1
xdebug.profiler_append = 0
xdebug.profiler_enable = 0
xdebug.profiler_enable_trigger = 0
xdebug.profiler_output_dir = “c:\xampp\tmp”
;xdebug.profiler_output_name = “cachegrind.out.%t-%s”
xdebug.remote_enable = 1
xdebug.remote_handler = “dbgp”
xdebug.remote_host = “127.0.0.1”
xdebug.remote_log=”c:\xampp\tmp\xdebug.txt”
xdebug.remote_port = 9000
xdebug.trace_output_dir = “c:\xampp\tmp”
; 3600 (1 hour), 36000 = 10h
xdebug.remote_cookie_expire_time = 36000

Configuring Web Browser

  • Install xdebug-helper extension in chrome browser [3] (there are other extensions for other browsers such as Firefox)
  • Go to extension options and change IDE key to PHPSTROM
  • Once you are logged to Joomla, switch to the Debug mode of plugin

Configuring Joomla to debug

Go to Global Configuration -> System and enable Debug System

Configuring PhpStrom

There are several ways of configuring remote debug from IDE side. Here I discuss on setting up as a remote debugger.

  • Go to debug configuration
  • Click + sign and click remote debugger
  • Click servers and add server’s debug configuration (xdebug host and port)
  • Add the correct IDE key and start debugger
  • Put some breakpoints and perform some actions Joomla!

Conclusion

There are several other ways of debugging Joomla as mention in [1]. Depending on the operating system, IDE and other facts, you may need to use different options.  I believe this article may help you to quickly setup debugging for Joomla! developments.

Reference

[1] How to debug your code – https://docs.joomla.org/How_to_debug_your_code

[2] Edit php.ini for XDebug – https://docs.joomla.org/Edit_PHP.INI_File_for_XDebug

[3] xdebug-helper – https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc

 

Advertisements

Simple Process Using Activiti

Introduction

Recently I came across this interesting area, “business processes and workflows”. Going further from simple workflows, this is a vast area to explore. There exists numbers of workflow engines which provides generic functionality to develop workflows for any use-case. In this article, I am discussing about my first experimental work done with Activiti [1]. For this experiment I have used version 5.18.0 (latest at the moment is 6.0.0).

Prerequisites

At first you need to install Java JDK and Tomcat in your machine. Then you need to download Activiti from official website [1], or github [2]. Copy activiti-explorer.war and activiti-rest.war files in to the webapps folder of Tomcat. Finally start the Tomcat and go to URL: http://localhost:8080/activiti-explorer. To login use demo user Kermit. (username: kermit, password: kermit)

Use-case

The use-case I’m going to discuss is a software feature development process of a small company. For this example, let’s assume there are 3 roles in the company as developers; who write codes, tech-leads; who review the code and QAs; who test the code. So the team members are as follows:

Developers: Mike, Jack

Tech-leads: Chris, Brian

QAs: Sandy, Alice

To cater this requirement, you have to go to “Manage” and use “groups” and “users” tabs to set up user accounts ans assign users to groups.

Implementation

Let’s develop this scenario with Activiti. Go to “Processes” tab, “Model Workspace” and start creating a new model. Activiti Explorer provides a convenient web-UI to develop models. You can drag and drop elements from panel and create the desired workflow. You can get the explanation about each element from the User Guide [3].

Final workflow looks like follows:

workflow

In the process I have used 3 User Tasks;

Develop features: assigned to “developers” group

Code Review: assigned to “tech-leads” group

Quality Checking: assigned to “qas” group

In addition to assigning, I have put form properties for Code Review and Quality Checking to indicate the user’s opinion.

Once you save the model, you can deploy it using the Activiti Explorer and “Deployed Process Definitions” shows the deployed model. You can start a process by clicking “Start process” button on top right.

activiti-ui.png

Now the process goes as described in the workflow model. You can open new web browser and login as one of the developers and claim the task. Once a developer completes the task, tech-leads and QAs can complete their tasks respectively. Below figure depicts the view of a developer.

jack's view

So, I have discussed a very brief amount of things that you can do with Activiti, but there’s much more.

Activiti access with Java: https://www.activiti.org/userguide/#_rest_support
(You need to sync activiti-explorer and activity-rest web apps to view results in activiti-explorer)

Explore history: https://www.activiti.org/userguide/#history

Eclipse designer: https://www.activiti.org/userguide/#activitiDesigner

Activiti REST API: https://www.activiti.org/userguide/#_rest_api

Conclusion

This post is to give you a start up with Activiti workflow engine. You can associate Activiti with your application and design flexible workflows according to your necessity.

References

[1] https://www.activiti.org/

[2] https://github.com/Activiti/Activiti/releases

[3] https://www.activiti.org/userguide/#bpmnConstructs

WebSocket with Spring Boot

Introduction

In this post I am going to talk briefly about developing a WebSocket based application using Spring Boot framework. WebSocket[1] is a full duplex protocol allows bi-directional communication. At the moment, widely using protocols such as HTTP is uni-directional and use long polling mechanisms to achieve bi-directional behavior. But using protocols such as WebSocket allows sending requests from server to client-side. However unlike HTTP, WebSocket does not form a strong application-level protocol. WebSocket sits as a thin layer on-top-of TCP protocol and allow application developers to come-up with a high-level messaging protocol design.

STOMP

Simple Text-Oriented Messaging Protocol (STOMP) is selected by the Spring framework for its WebSocket support. STOMP uses message brokers to provide bi-directional communication.

Server-side Code

Server-side code of a websocket server is as follows:


import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Controller
public class GreetingController {

@MessageMapping("/hello")
 @SendTo("/topic/greetings")
 public Greeting greeting(HelloMessage helloMessage) throws Exception {
 return new Greeting("Hello," + helloMessage.getName() + "!");
 }
}

In the above code @MessageMapping annotation is used to map the messages come with “/hello” in the path. @SendTo is used to specify the destination of the result. Here, HelloMessage and Greeting are bean classes which can be found in [2].

The server-side configuration is as follows:


@Configuration
@EnableWebSocketMessageBroker
public class WebsocketConfigurer extends AbstractWebSocketMessageBrokerConfigurer {

@Override
 public void configureMessageBroker(MessageBrokerRegistry registry) {
 registry.enableSimpleBroker("/topic");
 registry.setApplicationDestinationPrefixes("/app");
 }

@Override
 public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
 stompEndpointRegistry.addEndpoint("/gs-guide-websocket").withSockJS();
 }
}

WebsocketConfigurer class is annotated as the configuration class for the application. By configureMessageBroker method it enables message broker and add “/topic” as topic it holds. “/app” is used to identify messages which need to send to the controller.

In the second method, “/gs-guide-websocket” is used as a endpoint which clients can connect. So let’s move in to the client-side code. It contains 2 files, a static HTML and a JS file.

<html>
<head>
<title>Hello WebSocket</title>
	<link href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!--	<link href="/main.css" rel="stylesheet">-->
<script src="/webjars/jquery/jquery.min.js"></script>
    <script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
    <script src="/app.js"></script>
</head>
<body>
<noscript>
<h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!</h2>
</noscript>
<div id="main-content" class="container">
<div class="row">
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="connect">WebSocket connection:</label>
<button id="connect" class="btn btn-default" type="submit">Connect</button>
<button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect
</button>
</div>
</form>
</div>
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="name">What is your name?</label>
<input type="text" id="name" class="form-control" placeholder="Your name here...">
</div>
<button id="send" class="btn btn-default" type="submit">Send</button>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="conversation" class="table table-striped">
<thead>
<tr>
<th>Greetings</th>
</tr>
</thead>
<tbody id="greetings"></tbody>
</table>
</div>
</div>
</div>
</body>
</html>

var stompClient = null;

function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
}
else {
$("#conversation").hide();
}
$("#greetings").html("");
}

function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}

function disconnect() {
if (stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}

function sendName() {
stompClient.send("/app/hello", {}, JSON.stringify({'name': $("#name").val()}));
}

function showGreeting(message) {
$("#greetings").append("
<tr>
<td>" + message + "</td>
</tr>
");
}

$(function () {
$("form").on('submit', function (e) {
e.preventDefault();
});
$( "#connect" ).click(function() { connect(); });
$( "#disconnect" ).click(function() { disconnect(); });
$( "#send" ).click(function() { sendName(); });
});

Finally the pom file of the project is as follows:

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<groupId>com.buddhima.websocket</groupId>
<artifactId>websocket-try</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>

<properties>
<java.version>1.8</java.version>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

 

References

[1] WebSocket protocol RFC – https://tools.ietf.org/html/rfc6455

[2] Using WebSocket to build an interactive web application – https://spring.io/guides/gs/messaging-stomp-websocket/

[3] WebSocket Support – https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html

Microservices with Spring Boot

Introduction

Currently enterprise application development is more interested towards building them as microservices. This trend started about 2 years back and some organizations take this as an opportunity to do a complete re-write of their products. To help developing microservices, several organizations have done framework implementations. In here I am talking about using Spring Boot to create a very basic microservice.

Use-case

This system is about handling patient records. So it is more like an CRUD application. To persist data, I am using a Mongo DB (embedded version). First, let’s see what would be structure of this project.

proj-structure

Fist you need to create a project with the above structure. You may find maven arc-types which helps to do that. Next the pom file should be created properly. Here, I’m showing the important sections of the pom file.

 <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>

<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

 

Application.java file contains the main method to start the microservice. So it should looks like as follow:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

 public static void main(String[] args) {
     SpringApplication.run(Application.class, args);
 }
}

ApplicationConfig.java file is used to provide configurations to Spring framework. Here we provide the location of the service and REST-Template. So it should look like follows:

 

import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

import javax.inject.Named;

@Configuration
public class ApplicationConfig {
    @Named
    static class JerseyConfig extends ResourceConfig {
        public JerseyConfig() {
            this.packages("com.project.capsule.rest");
        }
    }

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        return restTemplate;
    }
}

Next we can extend MongoRepository and create PatientReportRepository. This is very interesting capability of Spring framework as it can convert method names in to SQL queries directly.

import com.project.capsule.bean.PatientReport;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;

public interface PatientReportRepository extends MongoRepository&lt;PatientReport, String&gt; {

 public List<PatientReport> findByName(String name);

 public List<PatientReport> findByNameLike(String name);

 public List<PatientReport> findByTimeBetween(long from, long to);

}

Now let’s create the bean class, PatientReport

 

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.springframework.data.annotation.Id;
import java.util.Map;

@JsonIgnoreProperties(ignoreUnknown = true)
public class PatientReport {

@Id
public String id;

public String name;
public int age;
public String sex;
public String doctorName;
public long time;
public String reportType;
public Map<String, Object> reportData;
}

Finally the service class, PatientReportService. You can define any number of methods and implement a custom logic.

import com.project.capsule.PatientReportRepository;
import com.project.capsule.bean.PatientReport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import javax.inject.Named;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.*;

@Named
@Path("/report")
public class PatientReportService {

@Autowired
private PatientReportRepository repository;

@POST
@Path("")
@Consumes(MediaType.APPLICATION_JSON)
public Response storePatientReport(@RequestBody PatientReport patientReport) {
repository.save(patientReport);
return Response.status(201).build();
}

@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public PatientReport retrievePatientReport(@PathParam("id") int id) {
PatientReport patientReport = repository.findOne(String.valueOf(id));
return patientReport;
}

@POST
@Path("find")
public List<PatientReport> findReports(@RequestParam Map<String, Object> map) {
List<PatientReport> patientReports = new ArrayList<PatientReport>();
Map<String, PatientReport> resultantMap = new HashMap<String, PatientReport>();
List<PatientReport> resultantReports;

if (map.containsKey("name") && map.get("name") != null) {
String patientName = (String) map.get("name");
if (!patientName.trim().equalsIgnoreCase("")) {
resultantReports = repository.findByNameLike(patientName);

for (PatientReport report : resultantReports)
resultantMap.put(report.id, report);

}
}
return patientReports;
}

}

Once you run the Application.java file, microservice will start from port 8080. You can change the post by giving argument “-Dserver.port=8090” etc. Thereafter you can use a REST client to send HTTP requests and see how it works!

References

[1] https://spring.io/blog/2015/07/14/microservices-with-spring

[2] http://blog.scottlogic.com/2016/11/22/spring-boot-and-mongodb.html

[3] https://dzone.com/articles/spring-boot-creating

WSO2 ESB Endpoint Error Handling

Introduction

WSO2 ESB can be used as an intermediary component to connect different systems. When connecting those systems the availability of those systems is a common issue. Therefore ESB has to handle those undesirable situations carefully and take relevant actions. To cater that requirement outbound-endpoints of the WSO2 ESB can be configured. In this article I discuss two common ways of configuring endpoints.

Two common approaches to configure endpoints are;

  1. Configure with just a timeout (without suspending endpoint)
  2. Configure with a suspend state

Configure with just a timeout

This would suitable if the endpoint failure is not very frequent.

Sample Configuration:

<endpoint name="SimpleTimeoutEP">
    <address uri="http://localhost:9000/StockquoteService">
    <timeout>
        <duration>2000</duration>
        <responseAction>fault</responseAction>
    </timeout>
    <suspendOnFailure>
        <errorCodes>-1</errorCodes>
        <initialDuration>0</initialDuration>
        <progressionFactor>1.0</progressionFactor>
        <maximumDuration>0</maximumDuration>
    </suspendOnFailure>
    <markForSuspension>
        <errorCodes>-1</errorCodes>
    </markForSuspension>
</address>
</endpoint>

 

In this case we only focus on the timeout of the endpoint. The endpoint will stay as Active for ever. If a response does not receive within duration, the responseAction triggers.

duration – in milliseconds

responseAction – when response comes to a time-out message one of the following actions trigger.

  • fault – calls the fault-sequence associated
  • discard – discards the response
  • none – will not take any specific action on response (default action)

The rest of the configuration avoids the endpoint going to suspend state.

If you specify responseAction as “fault”, you can define define customize way of informing the failure to the client in fault-handling sequence or store that message and retry later.

Configure with a suspend state

This approach is useful when connection failures are very often. By suspending endpoint, ESB can save resources without unnecessarily waiting for responses.

In this case endpoint goes through a state transition. The theory behind this behavior is the circuit-breaker pattern. Following are the three states:

  1. Active – Endpoint sends all requests to backend service
  2. Timeout – Endpoint starts counting failures
  3. Suspend – Endpoint limits sending requests to backend service

Sample Configuration:

<endpoint name="Suspending_EP">
    <address uri="http://localhost:9000/StockquoteServicet">
    <timeout>
        <duration>6000</duration>
    </timeout>
    <markForSuspension>
        <errorCodes>101504, 101505</errorCodes>
        <retriesBeforeSuspension>3</retriesBeforeSuspension>
        <retryDelay>1</retryDelay>
    </markForSuspension>
    <suspendOnFailure>
        <errorCodes>101500, 101501, 101506, 101507, 101508</errorCodes>
        <initialDuration>1000</initialDuration>
        <progressionFactor>2</progressionFactor>
        <maximumDuration>60000</maximumDuration>
    </suspendOnFailure>
</address>
</endpoint>

 

In the above configuration:

If endpoint error codes are 101504, 101505; endpoint is moved from active to timeout state.

When the endpoint is in timeout state, it tries 3 attempts with 1 millisecond delays.

If all those retry attempts fail, the endpoint will move to suspend state. If a retry succeed, then endpoint will move to active state.

If active endpoint receives error codes 101500, 101501, 101506, 101507, 101508; endpoint will directly move to suspend.

After endpoint somehow moves to suspend state, it waits initialDuration before attempting any furthermore. Thereafter it will determine the time period between requests according to following equation.

Min(current suspension duration * progressionFactor, maximumDuration)

In the equation, “current suspension duration” get updated for each reattempt.

Once endpoint succeed in getting a response to a request, endpoint will go back to active state.

If endpoint will get any other error codes (eg: 101503), it will not do any state transition, and remain in active state.

Conclusion

In this article I have shown two basic configurations that would be useful to configure endpoints of WSO2 ESB. You can refer WSO2 ESB documentation for implementing more complex patterns with endpoints.

References

WSO2 ESB Documentation: https://docs.wso2.com/display/ESB500/Endpoint+Error+Handling#EndpointErrorHandling-timeoutSettings

Timeout and Circuit Breaker Pattern in WSO2 Way: http://ssagara.blogspot.com/2015/05/timeout-and-circuit-breaker-pattern-in.html

Endpoint Error Codes: https://docs.wso2.com/display/ESB500/Error+Handling#ErrorHandling-codes

Endpoint Error Handling: http://wso2.com/library/articles/wso2-enterprise-service-bus-endpoint-error-handling/

Creating Geometry Compass Using JavaScript

Introduction

Few weeks back, I was asked to look around for existing geometry drawing tools. While searching, I found numbers of dynamic geometric construction tools which allows  drawing. Most of those projects are desktop-based, and few are web-based. Most of the web-based are reusing existing platforms such as GeoGebra.

In my research, I was focusing on the ruler and the compass tools which can be reused. Unfortunately I didn’t came across a web-based tool which can reuse. There were some good stuff, which are not reusable. Since most of the other web-based systems reuse GeoGebra, so they have the same limitations that GeoGebra has. Almost all reusable web-based tools have an issue with their compass, which was not user-friendly.

Problem

Geometry compass in most web-based tools allows you to draw arcs in one direction. Mostly anti-clockwise direction. This uni-directional compass tools were annoying for me while drawing constructions. Searching furthermore, I found Geometra (a desktop-based tool) has provided a reasonable solution for that. The compass in Geometra allows drawing arcs both sides, but allows drawing only small-arcs (less than 180 degrees). In my implementation I thought of bringing Geometra’s approach to web-based environment.

Background

For this implementation I used HTML5 canvas, and JavaScript. To make the implementation easier I added fabricjs library. Though FabricJs makes it easy to use HTML5 canvas, it has the limitation of representing Arcs. Therefore I extended its circle class to cater the requirement. Furthermore I used Compass class to handle properties of compass and event.js for handling mouse events.

Implementation

In this section, I’ll go through files which I discussed earlier. “Arc.class.js” file extends Circle class of fabricJs. Then I’ve overridden the initialize, render and toSVG methods to suite the requirement.

Arc.class.js


fabric.Arc = fabric.util.createClass(fabric.Circle, {
	type: 'arc',

	counterclockwise: false,

	initialize: function (options) {
		this.counterclockwise = options.counterclockwise;
		this.callSuper('initialize', options);
	},

	_render: function (ctx, noTransform) {
		ctx.beginPath();
		ctx.arc(noTransform ? this.left + this.radius : 0,
		      noTransform ? this.top + this.radius : 0,
		      this.radius,
		      this.startAngle,
		      this.endAngle, this.counterclockwise);
		this._renderFill(ctx);
		this._renderStroke(ctx);
    },

    toSVG: function(reviver) {
    	var markup = [];

		var rx = this.left + this.radius * Math.cos(this.startAngle);
		var ry = this.top + this.radius * Math.sin(this.startAngle);

		var ex = this.left + this.radius * Math.cos(this.endAngle);
		var ey = this.top + this.radius * Math.sin(this.endAngle);

		var svgPath = '';
	    if (!this.counterclockwise) {
	    	svgPath += '<path d=\"M'+rx+','+ry+' A'+this.radius+','+this.radius+' 0 0,1 '+ex+','+ey+'\" style=\"'+this.getSvgStyles()+'\"/>';
	    } else {
	    	// Exchange starting and ending points when it's counterclockwise
	    	svgPath += '<path d=\"M'+ex+','+ey+' A'+this.radius+','+this.radius+' 0 0,1 '+rx+','+ry+'\" style=\"'+this.getSvgStyles()+'\"/>';
	    }

	    markup.push(svgPath);

    	return reviver ? reviver(markup.join('')) : markup.join('');
    }
});

The above Arc class provides generic support for drawing arcs, similar to Line and Circle classes, already comes with FabricJs. To use Arc class, I created compass JavaScript file. It has 3 public methods: redraw; which is handling mouse movements when drawing starts, complete; which concludes the drawing and toSVG; which gives out the SVG representation of the arc drawn.

Compass.js


function Compass (mouseStart) {
	// 'c' for center, 'r' for radius, 'e' for end
	this.cx = this.rx = this.ex = mouseStart.x;
	this.cy = this.ry = this.ey = mouseStart.y;
	
	this.radius = 0;

	var points = [this.cx, this.cy, this.rx, this.ry];

	this.radiusLine = new fabric.Line(points, {				
										    strokeWidth: 2,
										    fill: 'black',
										    stroke: 'black',
										    strokeDashArray: [6, 3],
										    selectable: false
										});

	fabricCanvas.add(this.radiusLine);

	this.textObj = new fabric.Text('0', {
									        fontFamily: 'Times_New_Roman',
									        left: this.x1,
									        top: this.y1,
									        fontSize: 20,
									        originX: 'center'
									    });

	fabricCanvas.add(this.textObj);

	this.status = 'radius';
}

Compass.prototype = {
	constructor : Compass,

	redraw : function (mouse) { 

		if (this.status == 'radius') {
			this.rx = mouse.x;
		 	this.ry = mouse.y;

		 	this.radiusLine.set({ x2: this.rx, y2: this.ry });

		 	var tmp = addDistanceLabel (this.textObj, {x: this.cx, y:this.cy}, {x:this.rx, y:this.ry});

		 	fabricCanvas.renderAll();

		} else if (this.status = 'end') {
			this.ex = mouse.x;
			this.ey = mouse.y;

			this.endAngle = this._getAngle({ x:this.ex, y:this.ey })


			var angleDiff = this.endAngle - this.startAngle;

			if ((-Math.PI * 2 < angleDiff) && (angleDiff < -Math.PI)) {
				this.counterclockwise = false;
			} else if ((-Math.PI < angleDiff) && (angleDiff < 0)) {
				this.counterclockwise = true;
			} else if ((0 < angleDiff) && (angleDiff < Math.PI)) {
				this.counterclockwise = false;
			} else if ((Math.PI < angleDiff) && (angleDiff < Math.PI * 2)) {
				this.counterclockwise = true;
			}

			this.fabricObj.set( {endAngle: this.endAngle, counterclockwise: this.counterclockwise} );

			fabricCanvas.renderAll();
		}

	},

	complete : function () {

		if (this.status == 'radius') {

			fabricCanvas.remove(this.radiusLine);

			fabricCanvas.remove(this.textObj);

			fabricCanvas.renderAll();

			this.radius = Math.sqrt( Math.pow((this.rx-this.cx), 2) + Math.pow((this.ry-this.cy), 2) );

			this.startAngle = this._getAngle({ x:this.rx, y:this.ry });

			this.fabricObj = new fabric.Arc({
										left: this.cx,
										top: this.cy,
										radius: this.radius,
										startAngle: this.startAngle,
										endAngle: this.startAngle,
										counterclockwise: false,
										fill: '',
										stroke: 'black',
										originX: 'center',
								        originY: 'center',
								        selectable: false,
								        strokeDashArray: [6, 3]
									});

			fabricCanvas.add(this.fabricObj);

			this.status = 'end';

		} else if (this.status = 'end') {

			this.fabricObj.set({ strokeDashArray: [] });

			fabricCanvas.renderAll();

			drawings.push(this);
		}		
		
	},

	toSVG : function () {
	    return this.fabricObj.toSVG();
	},

	_getAngle : function (point) {
		var angleRequired = 0;

		// gets the actual angle from center
		if ((point.x-this.cx) == 0) {
			// handling special cases
			if (this.cy > point.y) { 
				angleRequired = Math.PI/2;
			} else if (this.cy < point.y) {
				angleRequired = -Math.PI/2;
			}
		} else {
			// in general cases
			angleRequired = Math.atan ((point.y-this.cy) / (point.x-this.cx));

			if ((this.cy < point.y) && (angleRequired < 0)) { // handle 2nd quadrant
				angleRequired = Math.PI - Math.abs(angleRequired);
			} else if ((this.cy > point.y) && (angleRequired > 0)) { // handle 3rd quadrant
				angleRequired = Math.PI + Math.abs(angleRequired);
			} else if ((this.cy > point.y) && (angleRequired < 0)) { // handle 4th quadrant
				angleRequired = 2*Math.PI - Math.abs(angleRequired);
			}
		}

		return angleRequired;
	}
}

For handling mouse events, I’ve created event JavaScript file. Depending on mouse events, this event file calls methods belongs to compass.

events.js


var fabricCanvas = new fabric.Canvas('sheet', { selection: false });
var selectedTool = '';
var toolState = '';
var toolPreviousState = '';
var instruction = $('#instructionText');

var currentTool = null;


var compassSettings = $('#compass_settings');
var compassSettingsState = $('input[name=compass-state]');

$('input[name=tool]').click(function() {
   $('input[name=tool]').removeClass('active_tool');
   $(this).addClass('active_tool');
});

fabricCanvas.on('mouse:down', function(e) {

	// Get mouse coordinates
	var mousePointer = getMousePointer(fabricCanvas, e);

	switch(selectedTool) {

		case 'compass' :

			switch(toolState) {
				case 'center' :
					
					currentTool = new Compass(mousePointer); 
					
					instruction.text('Select Radius Point');
					toolPreviousState = toolState;
					toolState = 'radius';

				break;
				case 'radius' :

					// do radius logic here
					currentTool.complete();

					// change to next
					// currentTool.addPoint(mousePointer);

					toolPreviousState = toolState;

					instruction.text('Select Ending Point');						
					toolState = 'end';
					

				break;
				case 'end' :

					// do end logic here
					currentTool.complete();

					instruction.text('Select Center Point');
					toolPreviousState = '';
					toolState = 'center';

				break;
			}

		break;		
	}
}, false);

fabricCanvas.on('mouse:move', function(e) {
	var mousePointer = getMousePointer(fabricCanvas, e);

	switch(selectedTool) {
		case 'compass' :
			switch(toolState) {
				case 'radius':
				case 'end' :
					currentTool.redraw(mousePointer);
				break;
			}

		break;
	}

}, false);

function getMousePointer (canvas, evt) {
    var mouse = canvas.getPointer(evt.e);
    var x = (mouse.x);
    var y = (mouse.y);
    return {
        x: x,
        y: y
    };
}


function addDistanceLabel (lineObj, start, end) {
	// change text label
 	var textX = start.x + ((end.x - start.x) / 2);
 	var textY = start.y + ((end.y - start.y) / 2);

 	var distance = Math.sqrt( Math.pow((end.x-start.x), 2) + Math.pow((end.y-start.y), 2) );
 	distance = (distance / 50.0).toFixed(1); // make it centimeters

 	lineObj.set( {left: textX, top: textY } );
 	lineObj.setText(distance + ' cm');
}


function initTool (toolName) {

	compassSettings.hide();

	switch (toolName) {
		case 'compass' :
			selectedTool = 'compass';
			toolState = 'center';
			instruction.text('Select Center Point');

			compassSettings.show();

			break;
	}
}

Finally you need to include dependencies in index.html file, which is shown below.

index.html


<!DOCTYPE html>
<html>
	<head>
	    <title>Mathematical Constructions</title>
	    <meta charset="utf-8"/>
	</head>

	<body>
		<h3>Geometrical Construction Drawing</h3>
		<canvas id="sheet" style="left:10px;top:10px;bottom:10px; border:1px solid #000000;" height="550" width="1280"></canvas>
		<br/>
		<div id="instructionText">Click on Compass</div>
		<br/>
		<input type="button" name="tool" class="btn btn-default" onclick="initTool('compass')" value="Compass">

		<script type="text/javascript" src="./js/jquery-3.1.1.min.js"></script>
		<script type="text/javascript" src="./js/fabric.js"></script>
		<script type="text/javascript" src="./js/events.js"></script>

		<!-- Extended shapes -->
		<script type="text/javascript" src="./js/Arc.class.js"></script>

		<!-- Tools for drawing -->
		<script type="text/javascript" src="./js/Compass.js"></script>

		<style type="text/css">
			.active_tool {background-color: gray}
		</style>
	</body>
</html>

To use this, you need to open index.html file in a browser. Then click Compass button, then click center and radius points respectively, and click on ending of arc. It’ll draw arcs shown as below.

compass_1

compass_2

Conclusion

In this post I shared my experience on how a bi-directional geometric compass is implemented for a web-based environment. Hope this will be helpful for you.

Resources

[1] GeoGebra – https://www.geogebra.org/

[2] Geometra – https://sourceforge.net/projects/geometra/

[3] HTML5 Canvas – http://www.w3schools.com/html/html5_canvas.asp

[4] SVG Path representation for Arcs – https://developer.mozilla.org/en/docs/Web/SVG/Tutorial/Paths#Arcs

 

 

Configuring ownCloud with XAMPP in Ubuntu

xampp_owncloud

Introduction

The ownCloud is a popular open-source, self-hosted file sync and sharing platform [1]. With ownCloud you can almost create a cloud storage of your own (private cloud). For that you need to installing ownCloud on top of an already existing server is the common way. For this base infrastructure, I’m using XAMPP [2], and please take a note of product versions below.

Prerequisites

  • Linux machine (I tested with Ubuntu 16.04)
  • XAMPP 7.0.8 (x64)
  • ownCloud 9.1.0

Note: I have experienced issues with XAMPP 7.0.9, missing module mod_ssl [3]. Also older ownCloud versions may not support newer PHP version coming up with XAMPP

Installation

Installing XAMPP is quite simple task, that you need to run downloaded “.run” executable in sudo mode.


chmod +x xampp-executable-name.run

sudo ./xampp-executable-name.run

You will get a GUI to configure further settings. Once you finished installing XAMPP, you can move on to installing ownCloud.

Installing ownCloud wan’t easy as thought. You’ll have to deal with several ownership level changes to directories.

First you need to download the ownCloud, and extract the zip file. Secondly you need to put it in to “htdocs” folder of XAMPP.

Then use following in terminal to go to super-user mode and creating the “data” folder inside owncloud folder you copied. Thereafter you need to give all privileges to “data” folder with “chmod”


sudo su

cd owncloud/

mkdir data chmod 777 data/

Now you can access “http://localhost/owncloud&#8221; URL from browser and configure admin account.

Once you have created the admin account, you need to make sure that data folder has right permissions. For that you need to change user, user-group ad permissions of the “data” folder.


chown daemon:daemon -R data/

chmod 770 -R data/

After completion, you’ll be able to see the welcome screen of ownCloud when navigating to “http://localhost/owncloud&#8221; URL.

References

[1] ownCloud – https://owncloud.org/

[2] XAMPP – https://www.apachefriends.org/index.html

[3] XAMPP issue – http://unix.stackexchange.com/questions/307364/xampp-apache-server-wont-start