1. #1
    Sencha User
    Join Date
    Dec 2012
    Posts
    12
    Answers
    1
    Vote Rating
    1
    jeremylauraire is on a distinguished road

      1  

    Default Answered: Drawing and charting interactive map not working

    Answered: Drawing and charting interactive map not working


    Hi Sencha community,

    I am trying to add an interactive map to my app. A good start in that development would be to use the interactive map of the USA in the "Drawing and charting example" in Sencha Try.

    I have embedded the code in a Ext.Panel, here is the code :

    Code:
    /**
     *
     * InteractiveMapView defintion
     * 
     *  in MyApp by Jeremy Lauraire
     *       v 0.1, 10/01/2012
     * 
     */
    Ext.define('MyApp.view.map.InteractiveMapView', {
        extend: 'Ext.Panel',
        xtype : 'interactivemapview',
        
        requires: ['Ext.draw.sprite.Path'],
        
        
        initialize: function() {
            
            this.callParent(arguments);
    
           (CODE FROM THE SENCHA TRY EXAMPLE GOES HERE)
        }
    
    });

    I get nothing but this error :

    TypeError: 'undefined' is not a constructor (evaluating 'new Ext.draw.Matrix()') Target.js:33

    Do you have any clue about this problem? I use Sencha Touch 2.1 Free Commercial Version with Sencha Cmd v3.0.0.250... and so far no problem with any other example given about charting and drawing on the Sencha doc...

    Thank you,
    Jay.
    Last edited by jeremylauraire; 13 Jan 2013 at 1:47 PM. Reason: error in code....

  2. Thank you for your help,

    Sorry I use a full GPL version of Sencha Touch 2.1 that embeds Ext.Chart.* and Ext.Draw.*... if not I would get an error on
    Code:
    requires: ['Ext.draw.sprite.Path']
    , right?

    After a while I figure out what the error was : I did not add the correct require config. But I must admit that the error log is not clear about that. So after adding the requires: ['Ext.Draw.Component'] config it works.

    If anyone is interested, here is the full code slightly modified of the Container :

    Code:
    /**
     *
     *      InteractiveMapView definition
     * 
     *     in MyApp by Jeremy Lauraire
     *          v 0.1, 10/01/2012
     * 
     */
    Ext.define('MyApp', {
        extend: 'Ext.Container',
        xtype : 'interactivemap',
        
        requires: [
        'Ext.draw.sprite.Path',
        'Ext.draw.Component'
        ],
        
        config: {
            layout: 'fit'
        },
        
        initialize: function() {
            
            this.callParent(arguments);
    
    
            var geo_data = [HERE GOES THE DATA];
            
            geo_data = geo_data.map(function (path) {
                item = Ext.create("Ext.draw.sprite.Path", {
                    path: path,
                    fx: {
                        duration: 200
                    },
                    highlightCfg: {
                        shadowColor: 'black',
                        shadowBlur: 8,
                        shadowOffsetX: 3,
                        shadowOffsetY: 3,
                        fillStyle: '#f18729',
                        zIndex: 100
                    },
                    modifiers: ['highlight']
                    
                });
                return item;
            });
    
    
            geo_data[0].setAttributes({
                highlight: true
            });
    
    
            var lastHighlight = geo_data[0];
    
    
            var interactiveMap = new Ext.draw.Component({
                sprites: geo_data,
                resizeHandler: function (size) {
                    var surface = this.getSurface('main'),
                    bbox = surface.getItems().getBBox(true);
                    scaling = Math.min((size.width - 30) / bbox.width, (size.height - 30) / bbox.height) * 0.95;
                    surface.setRegion([0, 0, size.width, size.height]);
                    surface.getItems().setAttributes({
                        fill: '#b7b6b6',
                        stroke: 'black',
                        translationX: -(bbox.x + bbox.width / 2) * scaling + size.width / 2,
                        translationY: -(bbox.y + bbox.height / 2) * scaling + size.height / 2,
                        scalingCenterX: 0,
                        scalingCenterY: 0,
                        scalingX: scaling,
                        scalingY: scaling
                    });
                },
                listeners: {
                    element: 'element',
                    tap: function (e) {
                        // hightlights the selected area...
                        
                        var items = this.getSurface().getItems().items;
                        
                        var i, ln = items.length,
                        item, mat = items[0].attr.inverseMatrix,
                        x = mat.x(e.pageX, e.pageY),
                        y = mat.y(e.pageX, e.pageY),
                        bbox, highlight = null;
                        for (i = 0; i < ln; i += 1) {
                            item = items[i];
                            bbox = item.getBBox(true);
                            if (bbox.x <= x && x <= bbox.x + bbox.width && bbox.y <= y && bbox.y <= bbox.y + bbox.height) {
                                if (item.attr.path.isPointInPath(x, y)) {
                                    highlight = item;
                                    break;
                                }
                            }
                        }
                        if (lastHighlight !== highlight) {
                            if (lastHighlight) {
                                lastHighlight.setAttributes({
                                    highlighted: false
                                });
                            }
                            if (highlight) {
                                highlight.setAttributes({
                                    highlighted: true
                                });
                            }
                            lastHighlight = highlight;
                        }
                    }
                }
            });
            
            this.add(interactiveMap);
           
            console.log('InteractiveMap:initialize');
        }
    });
    I can move on my new problem : build the geo data from a .svg file... Easy compare to debug this...

    Thank you,
    J.

  3. #2
    Sencha - Senior Forum Manager mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    37,074
    Answers
    3500
    Vote Rating
    854
    mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute mitchellsimoens has a reputation beyond repute

      1  

    Default


    The 2.1.0 commercial version doesn't come with Ext.chart.* and Ext.draw.* classes unless you buy support package that includes it like Sencha Complete.
    Mitchell Simoens @SenchaMitch
    Sencha Inc, Senior Forum Manager
    ________________
    Check out my GitHub, lots of nice things for Ext JS 4 and Sencha Touch 2
    https://github.com/mitchellsimoens

    Think my support is good? Get more personalized support via a support subscription. https://www.sencha.com/store/

    Need more help with your app? Hire Sencha Services services@sencha.com

    Want to learn Sencha Touch 2? Check out Sencha Touch in Action that is in print!

    When posting code, please use BBCode's CODE tags.

  4. #3
    Sencha User
    Join Date
    Dec 2012
    Posts
    12
    Answers
    1
    Vote Rating
    1
    jeremylauraire is on a distinguished road

      0  

    Default Forgot requires statement....

    Forgot requires statement....


    Thank you for your help,

    Sorry I use a full GPL version of Sencha Touch 2.1 that embeds Ext.Chart.* and Ext.Draw.*... if not I would get an error on
    Code:
    requires: ['Ext.draw.sprite.Path']
    , right?

    After a while I figure out what the error was : I did not add the correct require config. But I must admit that the error log is not clear about that. So after adding the requires: ['Ext.Draw.Component'] config it works.

    If anyone is interested, here is the full code slightly modified of the Container :

    Code:
    /**
     *
     *      InteractiveMapView definition
     * 
     *     in MyApp by Jeremy Lauraire
     *          v 0.1, 10/01/2012
     * 
     */
    Ext.define('MyApp', {
        extend: 'Ext.Container',
        xtype : 'interactivemap',
        
        requires: [
        'Ext.draw.sprite.Path',
        'Ext.draw.Component'
        ],
        
        config: {
            layout: 'fit'
        },
        
        initialize: function() {
            
            this.callParent(arguments);
    
    
            var geo_data = [HERE GOES THE DATA];
            
            geo_data = geo_data.map(function (path) {
                item = Ext.create("Ext.draw.sprite.Path", {
                    path: path,
                    fx: {
                        duration: 200
                    },
                    highlightCfg: {
                        shadowColor: 'black',
                        shadowBlur: 8,
                        shadowOffsetX: 3,
                        shadowOffsetY: 3,
                        fillStyle: '#f18729',
                        zIndex: 100
                    },
                    modifiers: ['highlight']
                    
                });
                return item;
            });
    
    
            geo_data[0].setAttributes({
                highlight: true
            });
    
    
            var lastHighlight = geo_data[0];
    
    
            var interactiveMap = new Ext.draw.Component({
                sprites: geo_data,
                resizeHandler: function (size) {
                    var surface = this.getSurface('main'),
                    bbox = surface.getItems().getBBox(true);
                    scaling = Math.min((size.width - 30) / bbox.width, (size.height - 30) / bbox.height) * 0.95;
                    surface.setRegion([0, 0, size.width, size.height]);
                    surface.getItems().setAttributes({
                        fill: '#b7b6b6',
                        stroke: 'black',
                        translationX: -(bbox.x + bbox.width / 2) * scaling + size.width / 2,
                        translationY: -(bbox.y + bbox.height / 2) * scaling + size.height / 2,
                        scalingCenterX: 0,
                        scalingCenterY: 0,
                        scalingX: scaling,
                        scalingY: scaling
                    });
                },
                listeners: {
                    element: 'element',
                    tap: function (e) {
                        // hightlights the selected area...
                        
                        var items = this.getSurface().getItems().items;
                        
                        var i, ln = items.length,
                        item, mat = items[0].attr.inverseMatrix,
                        x = mat.x(e.pageX, e.pageY),
                        y = mat.y(e.pageX, e.pageY),
                        bbox, highlight = null;
                        for (i = 0; i < ln; i += 1) {
                            item = items[i];
                            bbox = item.getBBox(true);
                            if (bbox.x <= x && x <= bbox.x + bbox.width && bbox.y <= y && bbox.y <= bbox.y + bbox.height) {
                                if (item.attr.path.isPointInPath(x, y)) {
                                    highlight = item;
                                    break;
                                }
                            }
                        }
                        if (lastHighlight !== highlight) {
                            if (lastHighlight) {
                                lastHighlight.setAttributes({
                                    highlighted: false
                                });
                            }
                            if (highlight) {
                                highlight.setAttributes({
                                    highlighted: true
                                });
                            }
                            lastHighlight = highlight;
                        }
                    }
                }
            });
            
            this.add(interactiveMap);
           
            console.log('InteractiveMap:initialize');
        }
    });
    I can move on my new problem : build the geo data from a .svg file... Easy compare to debug this...

    Thank you,
    J.

  5. #4
    Sencha User
    Join Date
    Jul 2012
    Posts
    51
    Answers
    2
    Vote Rating
    2
    tyladurdan is on a distinguished road

      0  

    Default Own geo Data?

    Own geo Data?


    How would we get our own Geo Data? I have seen in Adobe Illustrator the export SVG to code option but the output looks different.

    Is it possible to get a world map Geodata code from somewhere I wonder?

    Thanks

  6. #5
    Sencha User
    Join Date
    Dec 2012
    Posts
    12
    Answers
    1
    Vote Rating
    1
    jeremylauraire is on a distinguished road

      0  

    Default


    Interesting question #tylardurdan... that I have solved partially and still looking to improve...

    My goal is to build an interactive map, looking just like the USA map example presented in the Sencha Touch docs.... but with my own geo map (south of France to be clear or any other example).

    First thing to know is that a .svg file contains all those data : it is just a specific format based upon XML. But you can not use it without a parser.

    The question is : what is the proper parser to go from a .svg file found anywhere on the web to the proper geo data (which look like that "m 0.344 5.765 L 765.5 56.55............. L 656.77 45.4 z " to define the path in Ext.Draw.sprite.path)?

    I found the Raphael solution that works for a very simple example : http://readysetraphael.com. Basically, you provide the .svg file and the output is the file parsed to the Raphael format which is slightly different from what we need... so far I have manually extracted the data I need.

    That's it ! Then you can just set the geo_data var in the previous code and it should render your svg file as a Draw Component in the Panel.

    What I intend to do is to have a direct method to parse that kind of file.... work in progress unfortunately.

    Hope this is clear enough to help you.

    J.

  7. #6
    Sencha User
    Join Date
    Dec 2012
    Posts
    12
    Answers
    1
    Vote Rating
    1
    jeremylauraire is on a distinguished road

      0  

    Default Update : trouble with isPointInPath(x, y)

    Update : trouble with isPointInPath(x, y)


    Hi again,

    On the same example : interactive map of the USA... I have trouble with the isPointInPath method which does not respond correctly.

    The only differences with the original example is that I embedded it into a Container and I had to set fullscreen to false for the Ext.draw.Component...

    The code :
    Code:
                        for (i = 0; i < ln; i += 1) {
                            item = items[i];
                            bbox = item.getBBox(true);
    
    
                            if (bbox.x <= x && x <= bbox.x + bbox.width && bbox.y <= y && bbox.y <= bbox.y + bbox.height) {
                                if (item.attr.path.isPointInPath(x, y)) {  // THERE IT DOES NOT RETURN THE       PROPER TRUE/FALSE...
                                    highlight = item;
                                    break;
                                }
                            }
                        }
    If you have any clue about what I am doing wrong...

    This,
    J.

  8. #7
    Sencha Premium Member
    Join Date
    Oct 2011
    Location
    Duluth, MN
    Posts
    126
    Answers
    2
    Vote Rating
    4
    badgerb1 is on a distinguished road

      0  

    Default


    Hi Jeremy,

    I had the same problem. You'll need to use the e.browserEvent.offsetX and e.browserEvent.offsetY instead of pageX and pageY.

    x = mat.x(e.browserEvent.offsetX, e.browserEvent.offsetX),
    y = mat.y(e.browserEvent.offsetX, e.browserEvent.offsetY),

    Bob