пятница, 17 октября 2014 г.

Correctly display of negative ranges on ExtJS bar graphs

Bar graphs from Sencha ExtJS are great, but not without challenges for developers:) On of such issue I found during building graph with both, positive and negative, ranges. For example, your values are in the range [-100, 100].  In this case default behaviour of bar chart will be to have bars drawn from "zero" vertical line, but you need to be drawn from -100. My solution was to change values first to be "actualValue+100" (always positive in our case) and then make labels display correct value, it's done with customized render function:

axes: [{
        type: 'numeric',
        position: 'bottom',
        fields: 'score',
        minimum: 0,
        maximum: 200,
        majorTickSteps: 4,
        renderer: function (v) {
            // Make axis label display correct actual value
            return v - 100;
        }
    },
    ...

четверг, 16 октября 2014 г.

Crossbrowser solution to copy canvas elements

Sometimes you need to clone exisitng canvas elements to the new place, keeping its content. Solution for this problem is simple, but for IE additional workaround should be implemented, as always:)

/**
 * Copy canvas element image content.
 * @param oldCanvas old canvas element
 * @param newCanvas new canvas element
 * @param document current window document
 */
copyCanvas: function (oldCanvas, newCanvas, document) {
        if (oldCanvas) {
            try {
                // For IE browser replace canvas element with img with
                // source of old canvas, as drawImage causes
                // TypeMismatchError
                var agent = window.navigator.userAgent;
                // Check for both, IE11 and older versions
                if ((agent.indexOf('MSIE ') > -1) || (agent.indexOf('Trident/') > -1)) {
                    var oldImage = oldCanvas.toDataURL();
                    var img = document.createElement("img");
                    img.src = oldImage;
                    $(newCanvas).replaceWith(img);
                } else {
                    var context = newCanvas.getContext('2d');
                    context.drawImage(oldCanvas, 0, 0);
                }
            } catch (e) {
                console.log(e.name);
            }
        }
    }

вторник, 30 сентября 2014 г.

Sample app on modern Java and JS stack

I'm ready to announce that started open project with sample application, having Java EE stack on backend (including Spring and build up with Gradle) and AngularJS on front-end part. Now it uses embedded HSQLDB storage, but will be migrated to MongoDB. Checkout: https://github.com/maxaus/ee-grad

среда, 17 сентября 2014 г.

Printing grids in ExtJS

In many ExtJS applications grids have to be correctly printed, but as ExtJS has no such functionality out of the box, you should use some third-party or your own solution. One of the best start points is to use Ext.ux.Printer plugin. It can be used not only for grids, but also other components, but you need to define custom renderer classes for your component, see article http://edspencer.net/2009/07/28/extuxprinter-printing-for-any-ext/.  After that printing from your code is very simple:

   Ext.ux.Printer.print(MyApp.components.MyGrid);

четверг, 24 июля 2014 г.

Emoticons AngularJS directive

If you have ever developed web applications including social activity, like messaging, you definitely had a moment, when you need to add emoticons to your message board. Here is an example of AngularJS directive to convert symbols to emotional icons.
Emoticons map:
angular.module("myApp").value('Emoticons', {
  ':-)': 'http://www.freesmileys.org/smileys/smiley-basic/biggrin.gif',
  ':)': 'http://www.freesmileys.org/smileys/smiley-basic/biggrin.gif',
  ':D': 'http://www.freesmileys.org/smileys/smiley-basic/laugh.gif',
  ':-D': 'http://www.freesmileys.org/smileys/smiley-basic/laugh.gif',
  ':-|': 'http://www.freesmileys.org/smileys/smiley-basic/mellow.gif',
  ':|': 'http://www.freesmileys.org/smileys/smiley-basic/mellow.gif',
  ':-p': 'http://www.freesmileys.org/smileys/smiley-basic/tongue.gif',
  ':p': 'http://www.freesmileys.org/smileys/smiley-basic/tongue.gif',
  ':-(': 'http://www.freesmileys.org/smileys/smiley-basic/sad.gif',
  ':(': 'http://www.freesmileys.org/smileys/smiley-basic/sad.gif'
});

Directive:
angular.module("myApp").directive("withEmoticons", function (Emoticons, $timeout) {
  return {
    link: function postLink(scope, element, attrs) {

      scope.replaceEmoticons = function (text) {
        var patterns = [];
        var metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g;

        // build a regex pattern for each defined property
        for (var i in Emoticons) {
          if (Emoticons.hasOwnProperty(i)) { // escape metacharacters
            patterns.push('(' + i.replace(metachars, '\\$&') + ')');
          }
        }

        // build the regular expression and replace
        return text.replace(new RegExp(patterns.join('|'), 'g'), function (match) {
          return Emoticons[match] ?
            '' :
            match;
        });
      };

      $timeout(function () {
        element.html(scope.replaceEmoticons(element.html()));
      });

      scope.$watch(function () {
        return element.html();
      }, function onChange(newVal, oldVal) {
        if (newVal !== oldVal) {
          $timeout(function () {
            element.html(scope.replaceEmoticons(element.html()));
          });
        }
      });

    }
  };
});

In HTML:
{{message}}

пятница, 30 мая 2014 г.

Plain text AngularJS filter

Many times on different web projects there is an requirement to remove HTML tags from the text (that comes from some remote place and should be displayed on the web page). Here I will provide approach, how to do it through AngularJS filter. So, filter code itself:

/**
 * Filter removes HTML from given string value.
 */
angular.module("myApp").filter('plainText', function() {
  return function(val) {
    //remove html tags
    var s1 = val.replace(/<\/?[^>]+(>|$)/g, "");

    //translate special symbols
    var translate_re = /&(nbsp|amp|quot|lt|gt);/g;
    var translate = {"nbsp": " ","amp" : "&","quot": "\"","lt"  : "<","gt"  : ">"};
    return ( s1.replace(translate_re, function(match, entity) {
      return translate[entity];
    }) );
  };
});

And how it is being used on HTML page;
{{htmlMessage.body | plainText}}

пятница, 5 июля 2013 г.

Exporting Excel spreadsheet from Spring MVC application.

Here I will provide solution for common situation, when you need to export some kind of Excel doc (e.g. report) from web application built on Spring MVC framework. It's made with help of Apache POI library, which generates spreadsheet.

import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.springframework.web.servlet.view.document.AbstractExcelView;

/**
 * @author Maxim Baev
 */
public class ExcelRecipeWishListView extends AbstractExcelView {

 @Override
 protected void buildExcelDocument(Map model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
  Map productMap = (Map) model.get("productMap");
  //create a wordsheet
  HSSFSheet sheet = workbook.createSheet("Product list");

  HSSFRow header = sheet.createRow(0);
  CellStyle cellStyle = workbook.createCellStyle();
  Font font = workbook.createFont();
  font.setBoldweight(Font.BOLDWEIGHT_BOLD);
  cellStyle.setFont(font);
  Cell headerCell1 = header.createCell(0);
  headerCell1.setCellStyle(cellStyle);
  headerCell1.setCellValue("Product");
  Cell headerCell2 = header.createCell(1);
  headerCell2.setCellStyle(cellStyle);
  headerCell2.setCellValue("Quantity");

  int rowNum = 1;
  for (Map.Entry entry : productMap.entrySet()) {
   //create the row data
   HSSFRow row = sheet.createRow(rowNum++);
   row.createCell(0).setCellValue(entry.getKey());
   row.createCell(1).setCellValue(entry.getValue());
  }
  response.setHeader("Content-Disposition", "attachment; filename=\"product_list.xls\"");
 }
}

In Spring config spring-excel-views.xml it should be declared like that:

    
    

Then used in main config:

        

And finally on your controller:
    @RequestMapping(value = "/xls_wish_list")
    public ModelAndView exportWishListToExcel(HttpSession session) {
        List recipes = null;
        Map productMap = null;
        if (session.getAttribute("recipeIds") != null) {
            Set recipeIdSet = (Set) session.getAttribute("recipeIds");
            List recipeIds = new ArrayList(recipeIdSet);
            List searchCriteria = new ArrayList(1);
            searchCriteria.add(new IdSearchCriterion(recipeIds));
            recipes = recipeService.getRecipes(searchCriteria);

            productMap = makeProductMap(recipes);

        }
        //return excel view
        Map model = new HashMap(1);
        model.put("productMap", productMap);
        return new ModelAndView(new ExcelRecipeWishListView(), model);
    }