Completed
Push — master ( dd5351...9adbe5 )
by Yannick
53:50
created

PolylineTextPath.onAdd   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 1
b 0
f 0
1
/*
2
 * Leaflet.TextPath - Shows text along a polyline
3
 * Inspired by Tom Mac Wright article :
4
 * http://mapbox.com/osmdev/2012/11/20/getting-serious-about-svg/
5
 */
6
7
(function () {
8
9
var __onAdd = L.Polyline.prototype.onAdd,
0 ignored issues
show
Bug introduced by
The variable L seems to be never declared. If this is a global, consider adding a /** global: L */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
10
    __onRemove = L.Polyline.prototype.onRemove,
11
    __updatePath = L.Polyline.prototype._updatePath,
12
    __update = L.Polyline.prototype._update,
13
    __bringToFront = L.Polyline.prototype.bringToFront;
14
15
16
var PolylineTextPath = {
17
18
    onAdd: function (map) {
19
        __onAdd.call(this, map);
20
        this._textRedraw();
21
    },
22
23
    _update: function () {
24
        __update.call(this);
25
        this._textRedraw();
26
    },
27
28
    onRemove: function (map) {
29
        map = map || this._map;
30
        if (map && this._textNode)
31
            this._map._renderer._container.removeChild(this._textNode);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
32
        __onRemove.call(this, map);
33
    },
34
35
    bringToFront: function () {
36
        __bringToFront.call(this);
37
        this._textRedraw();
38
    },
39
40
    _updatePath: function () {
41
        __updatePath.call(this);
42
        this._textRedraw();
43
    },
44
45
    _textRedraw: function () {
46
        var text = this._text,
47
            options = this._textOptions;
48
        if (text) {
49
            this.setText(null).setText(text, options);
50
        }
51
    },
52
53
    setText: function (text, options) {
54
        this._text = text;
55
        this._textOptions = options;
56
57
        /* If not in SVG mode or Polyline not added to map yet return */
58
        /* setText will be called by onAdd, using value stored in this._text */
59
        if (!L.Browser.svg || typeof this._map === 'undefined') {
0 ignored issues
show
Bug introduced by
The variable L seems to be never declared. If this is a global, consider adding a /** global: L */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
60
          return this;
61
        }
62
63
        var defaults = {
64
            repeat: false,
65
            fillColor: 'black',
66
            attributes: {},
67
            below: false,
68
        };
69
        options = L.Util.extend(defaults, options);
70
71
        /* If empty text, hide */
72
        if (!text) {
73
            if (this._textNode && this._textNode.parentNode) {
74
                this._map._renderer._container.removeChild(this._textNode);
75
76
                /* delete the node, so it will not be removed a 2nd time if the layer is later removed from the map */
77
                delete this._textNode;
78
            }
79
            return this;
80
        }
81
82
        text = text.replace(/ /g, '\u00A0');  // Non breakable spaces
83
        var id = 'pathdef-' + L.Util.stamp(this);
84
        var svg = this._map._renderer._container;
85
        this._path.setAttribute('id', id);
86
87
        if (options.repeat) {
88
            /* Compute single pattern length */
89
            var pattern = document.createElementNS('http://www.w3.org/2000/svg', 'text');
90
            for (var attr in options.attributes)
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
91
                pattern.setAttribute(attr, options.attributes[attr]);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
92
            pattern.appendChild(document.createTextNode(text));
93
            svg.appendChild(pattern);
94
            var alength = pattern.getComputedTextLength();
95
            svg.removeChild(pattern);
96
97
            /* Create string as long as path */
98
            text = new Array(Math.ceil(this._path.getTotalLength() / alength)).join(text);
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
99
        }
100
101
        /* Put it along the path using textPath */
102
        var textNode = document.createElementNS('http://www.w3.org/2000/svg', 'text'),
103
          textPath = document.createElementNS('http://www.w3.org/2000/svg', 'textPath');
104
105
        var dy = options.offset || this._path.getAttribute('stroke-width');
106
107
        textPath.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", '#'+id);
108
        textNode.setAttribute('dy', dy);
109
        for (var attr in options.attributes)
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable attr already seems to be declared on line 90. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
110
            textNode.setAttribute(attr, options.attributes[attr]);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
111
        textPath.appendChild(document.createTextNode(text));
112
        textNode.appendChild(textPath);
113
        this._textNode = textNode;
114
115
        if (options.below) {
116
            svg.insertBefore(textNode, svg.firstChild);
117
        }
118
        else {
119
            svg.appendChild(textNode);
120
        }
121
122
        /* Center text according to the path's bounding box */
123
        if (options.center) {
124
            var textLength = textNode.getComputedTextLength();
125
            var pathLength = this._path.getTotalLength();
126
            /* Set the position for the left side of the textNode */
127
            textNode.setAttribute('dx', ((pathLength / 2) - (textLength / 2)));
128
        }
129
130
        /* Change label rotation (if required) */
131
        if (options.orientation) {
132
            var rotateAngle = 0;
133
            switch (options.orientation) {
134
                case 'flip':
135
                    rotateAngle = 180;
136
                    break;
137
                case 'perpendicular':
138
                    rotateAngle = 90;
139
                    break;
140
                default:
141
                    rotateAngle = options.orientation;
142
            }
143
144
            var rotatecenterX = (textNode.getBBox().x + textNode.getBBox().width / 2);
145
            var rotatecenterY = (textNode.getBBox().y + textNode.getBBox().height / 2);
146
            textNode.setAttribute('transform','rotate(' + rotateAngle + ' '  + rotatecenterX + ' ' + rotatecenterY + ')');
147
        }
148
149
        /* Initialize mouse events for the additional nodes */
150
        if (this.options.clickable) {
151
            if (L.Browser.svg || !L.Browser.vml) {
152
                textPath.setAttribute('class', 'leaflet-clickable');
153
            }
154
155
            /*L.DomEvent.on(textNode, 'click', this._onMouseClick, this);
156
157
            var events = ['dblclick', 'mousedown', 'mouseover',
158
                          'mouseout', 'mousemove', 'contextmenu'];
159
            for (var i = 0; i < events.length; i++) {
160
                L.DomEvent.on(textNode, events[i], this._fireMouseEvent, this);
161
            }*/
162
        }
163
164
        return this;
165
    }
166
};
167
168
L.Polyline.include(PolylineTextPath);
169
170
L.LayerGroup.include({
171
    setText: function(text, options) {
172
        for (var layer in this._layers) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
173
            if (typeof this._layers[layer].setText === 'function') {
174
                this._layers[layer].setText(text, options);
175
            }
176
        }
177
        return this;
178
    }
179
});
180
181
182
183
})();
184