# Polyline

# Usage

let data = {
    "type": "FeatureCollection",
    "features": [
        {
            "id": "1",
            "type": "Feature",
            "properties": {
                "name": "polyline1",
                "color": "#00ffff"
            },
            "geometry": {
                "coordinates": [
                    [
                        3006.0952985307595,
                        15198.972934052355
                    ],
                    [
                        12606.64046359223,
                        9285.59366571666
                    ],
                    [
                        4745.324495099878,
                        3720.060236694666
                    ],
                    [
                        3006.0952985307595,
                        15198.972934052355
                    ]
                ],
                "type": "LineString"
            }
        },
        {
            "id": "2",
            "type": "Feature",
            "properties": {
                "name": "polyline2",
                "color": "#ff00ff"
            },
            "geometry": {
                "coordinates": [
                    [
                        19841.833921319492,
                        13807.589576796912
                    ],
                    [
                        19841.833921319492,
                        4207.0444117340885
                    ],
                    [
                        26172.62819683108,
                        4207.0444117340885
                    ],
                    [
                        26172.62819683108,
                        13807.589576796912
                    ],
                    [
                        19841.833921319492,
                        13807.589576796912
                    ]
                ],
                "type": "LineString"
            }
        }
    ]
}
let polyline = new vjmap.Polyline({
    data: map.toLngLat(data), // Convert CAD geometry coordinates to render longitude/latitude
    // Use red when hover state, otherwise use 'color' from properties
    lineColor: ['case', ['to-boolean', ['feature-state', 'hover']], 'red', ['get', 'color']],
    lineWidth: 3,
    isHoverPointer: true,
    isHoverFeatureState: true
});
polyline.addTo(map);
polyline.clickLayer(e => map.logInfo(`You clicked No. ${e.features[0].id}, name: ${e.features[0].properties.name}, color: ${e.features[0].properties.color} `))
polyline.hoverPopup(f => `<h3>ID: ${f.properties.name}</h3>Color: ${f.properties.color}`, { anchor: 'bottom' });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
显示代码
全屏显示


Alternatively, create the data source first, then create the line layer, e.g.

map.addSource("lines", {
    type: "geojson",
    data: data
});
map.addLayer({
    id: 'lineLayers',
    source: 'lines',
    type: 'line',
    "layout": {
        "line-cap": "square", //butt pointed, round rounded, square flat
        "line-join": "round" //bevel flat corner, round rounded corner, miter sharp corner
    },
    "paint": {
        "line-width": 3, //width
        "line-color": ['case', ['to-boolean', ['feature-state', 'hover']], 'red', ['get', 'color']] //color
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Or use camelCase for properties, no need to distinguish layout vs paint

map.addGeoJSONSource("lines", data);
map.addLineLayer("route", "lines", {
    lineCap: "square", //butt pointed, round rounded, square flat
    lineJoin: "round", //bevel flat corner, round rounded corner, miter sharp corner
    lineWidth: 3, //width
    lineColor: ['case', ['to-boolean', ['feature-state', 'hover']], 'red', ['get', 'color']] //color
})
1
2
3
4
5
6
7

When using this approach of creating data source and layer, listen to map layer events for event handling

map.on("click", layerId, e => {})
1

# Common Methods

Use setData to modify data

polyline.setData(newDataJson);
1

Get layer ID and data source ID

// Get layer ID
polyline.getLayerId()
// Get data source ID
polyline.getSourceId()
1
2
3
4

Show or hide

// Show
polyline.show()
// Hide
polyline.hide()
1
2
3
4

Remove

// Remove
polyline.remove()
1
2

image-20240928152216876

Single polyline (opens new window)

Batch draw different types of polylines (opens new window)

Path animation (opens new window)

Gradient line (opens new window)

Polyline line type settings (opens new window)

Line pattern fill animation (opens new window)

Polyline to polygon (opens new window)

# Type Definitions

/**
 * Create polyline.
 *
 **/
export  class Polyline extends OverlayLayerBase {
    options: PolylineOptions;
    constructor(options: PolylineOptions);
    addTo(map: Map, beforeId?: string): void;
    /** Replace the current data of the GeoJSON layer.
     @param {GeoJSON} [data] GeoJSON object to set. If not provided, defaults to an empty FeatureCollection.
     */
    setData(data: PointGeoJsonInput | PointGeoJsonInput[] | GeoJsonGeomertry | GeoPointLike | any): void;
    setLineCap(value: DataDrivenPropertyValueSpecification<"butt" | "round" | "square">): this;
    getLineCap(): DataDrivenPropertyValueSpecification<"butt" | "round" | "square">;
    setLineJoin(value: DataDrivenPropertyValueSpecification<"bevel" | "round" | "miter">): this;
    getLineJoin(): DataDrivenPropertyValueSpecification<"bevel" | "round" | "miter">;
    setLineMiterMimit(value: PropertyValueSpecificationEx<number>): this;
    getLineMiterMimit(): PropertyValueSpecificationEx<number>;
    setLineRoundLimit(value: PropertyValueSpecificationEx<number>): this;
    getLineRoundLimit(): PropertyValueSpecificationEx<number>;
    setLineSortKey(value: DataDrivenPropertyValueSpecification<number>): this;
    getLineSortKey(): DataDrivenPropertyValueSpecification<number>;
    setLineOpacity(value: DataDrivenPropertyValueSpecification<number>): this;
    getLineOpacity(): DataDrivenPropertyValueSpecification<number>;
    setLineColor(value: DataDrivenPropertyValueSpecification<ColorSpecification>): this;
    getLineColor(): DataDrivenPropertyValueSpecification<ColorSpecification>;
    setLineTranslate(value: PropertyValueSpecificationEx<[number, number]>): this;
    getLineTranslate(): PropertyValueSpecificationEx<[number, number]>;
    setLineTranslateAnchor(value: PropertyValueSpecificationEx<"map" | "viewport">): this;
    getLineTranslateAnchor(): PropertyValueSpecificationEx<"map" | "viewport">;
    setLineWidth(value: DataDrivenPropertyValueSpecification<number>): this;
    getLineWidth(): DataDrivenPropertyValueSpecification<number>;
    setLineGapWidth(value: DataDrivenPropertyValueSpecification<number>): this;
    getLineGapWidth(): DataDrivenPropertyValueSpecification<number>;
    setLineOffset(value: DataDrivenPropertyValueSpecification<number>): this;
    getLineOffset(): DataDrivenPropertyValueSpecification<number>;
    setLineBlur(value: DataDrivenPropertyValueSpecification<number>): this;
    getLineBlur(): DataDrivenPropertyValueSpecification<number>;
    setLineDasharray(value: DataDrivenPropertyValueSpecification<number[]>): this;
    getLineDasharray(): DataDrivenPropertyValueSpecification<number[]>;
    setLinePattern(value: DataDrivenPropertyValueSpecification<ResolvedImageSpecification>): this;
    getLinePattern(): DataDrivenPropertyValueSpecification<ResolvedImageSpecification>;
    setLineGradient(value: ExpressionSpecificationEx): this;
    getLineGradient(): ExpressionSpecificationEx;
}



export  class OverlayLayerBase {
    sourceId?: string;
    layerId?: string;
    _map?: Map;
    constructor();
    addTo(map: Map, beforeId?: string): void;
    /**
     * Get data source ID
     * @return {string | undefined}
     */
    getSourceId(): string | undefined;
    /**
     * Get layer ID
     * @return {string | undefined}
     */
    getLayerId(): string | undefined;
    /**
     * Get data source data
     * @return {GeoJsonGeomertry | undefined}
     */
    getData(): GeoJsonGeomertry | undefined;
    remove(): void;
    /** Set map cursor to "pointer" when mouse hovers over these layers.
     @returns A function to remove the handler.
     * @param layerOrLayers
     */
    hoverPointer(): void;
    /**
     Update feature state in connected source when mouse hovers over a feature in these layers.
     * @param enterCb
     * @param leaveCb
     */
    hoverFeatureState(enterCb?: (arg0: {}) => void, leaveCb?: (arg0: {}) => void): void;
    /** Show a popup when mouse hovers over a feature in these layers.
     @param htmlFunc Function that receives feature and popup, returns HTML.
     @param {Object<PopupOptions>} popupOptions Options passed to `Popup()` to customise popup.
     @example hoverPopup(f => `<h3>${f.properties.Name}</h3> ${f.properties.Description}`, { anchor: 'left' });
     */
    hoverPopup(htmlFunc: any, popupOptions?: PopupOptions): any;
    /** Show a popup when clicking a feature in these layers.
     @param htmlFunc Function that receives feature and popup, returns HTML.
     @param {Object<PopupOptions>} popupOptions Options passed to `Popup()` to customise popup.

     @returns A function that removes the handler.
     @example clickPopup(f => `<h3>${f.properties.Name}</h3> ${f.properties.Description}`, { maxWidth: 500 });

     */
    clickPopup(htmlFunc: (arg0: {}) => void, popupOptions?: PopupOptions): any;
    /** Trigger callback when clicking a feature in these layers.
     @param {function} cb Callback that receives event with .features property
     @returns A function that removes the handler.
     */
    clickLayer(cb: any): any;
    /** Trigger callback when mouse hovers over a feature in these layers.
     @returns A function to remove the handler.
     */
    hoverLayer(cb: any): any;
    /**
     * Make the given layer visible.
     * @param layer
     */
    show(): void;
    /**
     * Make the given layer invisible.
     * @param layer
     */
    hide(): void;
    /** Hide or show the given layer based on parameter.
     @param {boolean} state True for visible, false for hidden.
     */
    toggle(state: boolean): boolean;
    /** Set paint or layout property on one or more layers.
     @example setProperty('fillOpacity', 0.5)
     */
    setProperty(prop: string | object, value?: any): void;
    /** Get layer definition for given layer ID according to style spec.
     */
    getLayerStyle(): LayerSpecification;
    /**
     * Set layer style
     * @param layer
     * @param style
     */
    setLayerStyle(style: any): void;
    /** Replace the filter of a layer.
     @param {Array} filter New filter to set.
     @example setFilter(['==','level','0']]);
     */
    setFilter(filter: FilterSpecification): void;
}

export  interface OverlayLayerBaseOptions {
    sourceId?: string;
    sourceLayer?: string;
    layerId?: string;
    minzoom?: number;
    maxzoom?: number;
    filter?: any;
    visibility?: "visible" | "none";
    isHoverPointer?: boolean;
    isHoverFeatureState?: boolean;
}



export  type LineLayerSpecification = {
    id: string;
    type: "line";
    metadata?: unknown;
    source: string;
    "source-layer"?: string;
    minzoom?: number;
    maxzoom?: number;
    filter?: FilterSpecification;
    layout?: {
        "line-cap"?: DataDrivenPropertyValueSpecification<"butt" | "round" | "square">;
        "line-join"?: DataDrivenPropertyValueSpecification<"bevel" | "round" | "miter">;
        "line-miter-limit"?: PropertyValueSpecificationEx<number>;
        "line-round-limit"?: PropertyValueSpecificationEx<number>;
        "line-sort-key"?: DataDrivenPropertyValueSpecification<number>;
        visibility?: "visible" | "none";
    };
    paint?: {
        "line-opacity"?: DataDrivenPropertyValueSpecification<number>;
        "line-color"?: DataDrivenPropertyValueSpecification<ColorSpecification>;
        "line-translate"?: PropertyValueSpecificationEx<[number, number]>;
        "line-translate-anchor"?: PropertyValueSpecificationEx<"map" | "viewport">;
        "line-width"?: DataDrivenPropertyValueSpecification<number>;
        "line-gap-width"?: DataDrivenPropertyValueSpecification<number>;
        "line-offset"?: DataDrivenPropertyValueSpecification<number>;
        "line-blur"?: DataDrivenPropertyValueSpecification<number>;
        "line-dasharray"?: DataDrivenPropertyValueSpecification<Array<number>>;
        "line-pattern"?: DataDrivenPropertyValueSpecification<ResolvedImageSpecification>;
        "line-gradient"?: ExpressionSpecificationEx;
    };
};

export  type LineLayerStyleProp = {
    metadata?: unknown;
    source?: string;
    sourceLayer?: string;
    minzoom?: number;
    maxzoom?: number;
    filter?: FilterSpecification;
    lineCap?: DataDrivenPropertyValueSpecification<"butt" | "round" | "square">;
    lineJoin?: DataDrivenPropertyValueSpecification<"bevel" | "round" | "miter">;
    lineMiterMimit?: PropertyValueSpecificationEx<number>;
    lineRoundLimit?: PropertyValueSpecificationEx<number>;
    lineSortKey?: DataDrivenPropertyValueSpecification<number>;
    visibility?: "visible" | "none";
    lineOpacity?: DataDrivenPropertyValueSpecification<number>;
    lineColor?: DataDrivenPropertyValueSpecification<ColorSpecification>;
    lineTranslate?: PropertyValueSpecificationEx<[number, number]>;
    lineTranslateAnchor?: PropertyValueSpecificationEx<"map" | "viewport">;
    lineWidth?: DataDrivenPropertyValueSpecification<number>;
    lineGapWidth?: DataDrivenPropertyValueSpecification<number>;
    lineOffset?: DataDrivenPropertyValueSpecification<number>;
    lineBlur?: DataDrivenPropertyValueSpecification<number>;
    lineDasharray?: DataDrivenPropertyValueSpecification<Array<number>>;
    linePattern?: DataDrivenPropertyValueSpecification<ResolvedImageSpecification>;
    lineGradient?: ExpressionSpecificationEx;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210