diff --git a/addon/components/google-maps-markup/component.js b/addon/components/google-maps-markup/component.js
index 938522f..da47cfc 100644
--- a/addon/components/google-maps-markup/component.js
+++ b/addon/components/google-maps-markup/component.js
@@ -8,8 +8,10 @@ import overlayToFeature from '../../utils/overlay-to-feature';
import featureCenter from '../../utils/feature-center';
import initMeasureLabel from '../../utils/init-measure-label';
import MapLabel from '../../utils/map-label';
+import Marker from '../../utils/marker';
import DynamicLabel from '../../utils/dynamic-label';
import labelPlotter from '../../utils/label-plotter';
+import hoverColor from '../../utils/hover-color';
if (!window.google) {
throw new Error('Sorry, but `google` defined globally is required for this addon');
@@ -191,7 +193,7 @@ export default Ember.Component.extend(ParentMixin, {
poly.getPath().push(e.latLng);
});
- google.maps.event.addListenerOnce(map, 'mouseup', (e) => {
+ google.maps.event.addListenerOnce(map, 'mouseup', () => {
google.maps.event.removeListener(move);
poly.setMap(null);
@@ -214,6 +216,7 @@ export default Ember.Component.extend(ParentMixin, {
},
actions: {
+
updateOptionValue(tool, prop, value) {
set(tool, prop, value);
},
@@ -233,6 +236,9 @@ export default Ember.Component.extend(ParentMixin, {
},
changeTool(toolId) {
+ this.resetAllLayers();
+ this.clearListeners();
+
let markupDataService = this.get('markupData');
let activeLayer = this.get('activeLayer');
let map = this.get('map');
@@ -244,9 +250,6 @@ export default Ember.Component.extend(ParentMixin, {
this.set('drawFinished', false);
markupDataService.set('activeTool', tool.id);
- this.resetAllLayers();
- this.clearListeners();
-
if (activeLayer) {
if (tool.id === 'pan') {
activeLayer.data.setDrawingMode(null);
@@ -255,7 +258,6 @@ export default Ember.Component.extend(ParentMixin, {
let clickListener = activeLayer.data.addListener('click', event => {
let childComponents = this.get('childComponents');
- let results = this.get('results');
let found = childComponents.find(function (comp) {
return comp.get('data').feature.getId() === event.feature.getId();
});
@@ -282,6 +284,8 @@ export default Ember.Component.extend(ParentMixin, {
event.stop();
});
listeners.pushObjects([ mapListener, dataListener ]);
+ } else if (tool.dataId === 'Point') {
+ activeLayer.data.setDrawingMode(tool.dataId);
} else if (tool.dataId) {
let style = Ember.copy(tool.style);
@@ -332,6 +336,8 @@ export default Ember.Component.extend(ParentMixin, {
if (result.type === 'text') {
textGeoJson.removeObject(result.geojson);
}
+ } else if (result.markerData) {
+ result.markerData.setMap(null);
}
});
@@ -352,6 +358,9 @@ export default Ember.Component.extend(ParentMixin, {
if (result.type === 'text') {
result.feature.setMap(null);
textGeoJson.removeObject(result.geojson);
+ } else if (result.type === 'marker') {
+ result.markerData.setMap(null);
+ layer.data.remove(result.feature);
} else {
layer.data.remove(result.feature);
}
@@ -462,6 +471,11 @@ export default Ember.Component.extend(ParentMixin, {
scaledSize: new google.maps.Size(22, 40),
}
};
+
+ if(data.hoverStyle){
+ style = data.hoverStyle;
+ }
+
} else if (data.type === 'text') {
data.feature.highlight();
} else {
@@ -707,16 +721,85 @@ export default Ember.Component.extend(ParentMixin, {
let plotter;
let onClick = run.bind(this, (event) => {
+ let activeLayer = this.get('activeLayer');
let toolId = this.get('toolId');
+ let tool = this.getTool(toolId);
let mode = this.get('mode');
let mapDiv = map.getDiv();
let target = event.target;
let withinMap = mapDiv.contains(target);
+ let results = this.get('results');
if (mode === 'draw') {
if (withinMap && toolId === 'freeFormPolygon') {
this.enableFreeFormPolygon();
+ } else if (withinMap && toolId === 'marker') {
+ let length = results.get('length');
+ let arrayIndexOffSet = 1;
+ let lastObjectIndex = length - arrayIndexOffSet;
+ let data = results.get('lastObject');
+
+ let iconObj = tool.icons.find(function(iconObj){
+ return iconObj.id === tool.icon.id;
+ });
+
+ let markerObj = tool.markers.find(function(markerObj){
+ return markerObj.id === tool.marker.id;
+ });
+
+ if (markerObj.id !== 'default') {
+
+ let style = {
+ icon: {
+ path: markerObj.path,
+ fillColor: tool.style.color,
+ fillOpacity: 1,
+ strokeColor: '',
+ strokeWeight: 0,
+ scaledSize: new google.maps.Size(22, 40)
+ },
+ map_icon_label: '' + markerObj.id + ''
+ };
+
+ let hoverStyle = {
+ icon: {
+ path: markerObj.path,
+ fillColor: hoverColor(tool.style.color),
+ fillOpacity: 1,
+ strokeColor: '',
+ strokeWeight: 0,
+ scaledSize: new google.maps.Size(22, 40)
+ }
+ };
+
+ if (tool.icon.id !== 'default') {
+ var marker = new Marker({
+ position: calculateLatLng(map, event),
+ map: map,
+ icon: {
+ path: markerObj.path,
+ fillColor: tool.style.color,
+ fillOpacity: 1,
+ strokeColor: '',
+ strokeWeight: 0,
+ scaledSize: new google.maps.Size(22, 40)
+ },
+ map_icon_label: '' + iconObj.id + ''
+ })
+
+ data.markerData = marker;
+
+ // To add the marker to the map, call setMap();
+ marker.setMap(map);
+ }
+
+ data.hoverStyle = hoverStyle;
+ data.style = style;
+ results[lastObjectIndex] = data;
+ activeLayer.data.overrideStyle(data.feature, style);
+ }
}
+
return;
}
diff --git a/addon/components/google-maps-markup/template.hbs b/addon/components/google-maps-markup/template.hbs
index 1813f4f..2a6f60d 100644
--- a/addon/components/google-maps-markup/template.hbs
+++ b/addon/components/google-maps-markup/template.hbs
@@ -34,6 +34,7 @@
{{#each activeTool.options as |opt|}}
{{#if (is-equal opt.type 'color')}}
+ {{#unless (is-equal activeTool.icon 'default')}}
{{color-palette selected=(get activeTool opt.id) onselect=(action 'updateOptionValue' activeTool opt.id)}}
+ {{/unless}}
+
+ {{/if}}
+ {{#if (is-equal opt.type 'Marker')}}
+
+ {{/if}}
+ {{#unless (is-equal activeTool.marker.id 'default')}}
+ {{#if (is-equal opt.type 'icon')}}
+
{{/if}}
+ {{/unless}}
+
{{/each}}
{{/if}}
diff --git a/addon/components/markup-result-item/component.js b/addon/components/markup-result-item/component.js
index 94ba6e8..8f886ac 100644
--- a/addon/components/markup-result-item/component.js
+++ b/addon/components/markup-result-item/component.js
@@ -8,7 +8,6 @@ import featureCenter from '../../utils/feature-center';
const {
on,
run,
- set,
computed
} = Ember;
diff --git a/addon/utils/hover-color.js b/addon/utils/hover-color.js
new file mode 100644
index 0000000..36898d2
--- /dev/null
+++ b/addon/utils/hover-color.js
@@ -0,0 +1,87 @@
+
+/* hexToComplimentary : Converts hex value to HSL, shifts
+ * hue by 180 degrees and then converts hex, giving complimentary color
+ * as a hex value
+ * @param [String] hex : hex value
+ * @return [String] : complimentary color as hex value
+ */
+export default function hoverColor(hex) {
+ // Convert hex to rgb
+ var rgb = 'rgb(' + (hex = hex.replace('#', '')).match(new RegExp('(.{' + hex.length/3 + '})', 'g')).map(function(l) { return parseInt(hex.length%2 ? l+l : l, 16); }).join(',') + ')';
+
+ // Get array of RGB values
+ rgb = rgb.replace(/[^\d,]/g, '').split(',');
+
+ var r = rgb[0], g = rgb[1], b = rgb[2];
+
+ // Convert RGB to HSL
+ r /= 255.0;
+ g /= 255.0;
+ b /= 255.0;
+ var max = Math.max(r, g, b);
+ var min = Math.min(r, g, b);
+ var h, s, l = (max + min) / 2.0;
+
+ if(max === min) {
+ h = s = 0; //achromatic
+ } else {
+ var d = max - min;
+ s = (l > 0.5 ? d / (2.0 - max - min) : d / (max + min));
+
+ if(max === r && g >= b) {
+ h = 1.0472 * (g - b) / d ;
+ } else if(max === r && g < b) {
+ h = 1.0472 * (g - b) / d + 6.2832;
+ } else if(max === g) {
+ h = 1.0472 * (b - r) / d + 2.0944;
+ } else if(max === b) {
+ h = 1.0472 * (r - g) / d + 4.1888;
+ }
+ }
+
+ h = h / 6.2832 * 360.0 + 0;
+
+ // Shift hue to opposite side of wheel and convert to [0-1] value
+ h+= 180;
+ if (h > 360) { h -= 360; }
+ h /= 360;
+
+ // Convert h s and l values into r g and b values
+ if(s === 0){
+ r = g = b = l; // achromatic
+ } else {
+ var hue2rgb = function hue2rgb(p, q, t){
+ if(t < 0) {
+ t += 1;
+ }
+ if(t > 1){
+ t -= 1;
+ }
+ if(t < 1/6) {
+ return p + (q - p) * 6 * t;
+ }
+ if(t < 1/2) {
+ return q;
+ }
+ if(t < 2/3) {
+ return p + (q - p) * (2/3 - t) * 6;
+ }
+ return p;
+ };
+
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+
+ r = hue2rgb(p, q, h + 1/3);
+ g = hue2rgb(p, q, h);
+ b = hue2rgb(p, q, h - 1/3);
+ }
+
+ r = Math.round(r * 255);
+ g = Math.round(g * 255);
+ b = Math.round(b * 255);
+
+ // Convert r b and g values to hex
+ rgb = b | (g << 8) | (r << 16);
+ return "#" + (0x1000000 | rgb).toString(16).substring(1);
+}
\ No newline at end of file
diff --git a/addon/utils/marker-label.js b/addon/utils/marker-label.js
new file mode 100644
index 0000000..978cf49
--- /dev/null
+++ b/addon/utils/marker-label.js
@@ -0,0 +1,65 @@
+class MarkerLabel extends google.maps.OverlayView {
+ constructor(options) {
+ super(...arguments);
+
+ var self = this;
+ this.setValues(options);
+
+ this.position = options.position;
+
+ // Create the label container
+ this.div = document.createElement('div');
+ this.div.className = '';
+
+ // Trigger the marker click handler if clicking on the label
+ google.maps.event.addDomListener(this.div, 'click', function(e){
+ (e.stopPropagation) && e.stopPropagation();
+ google.maps.event.trigger(self.marker, 'click');
+ });
+ }
+
+ onAdd() {
+ var pane = this.getPanes().overlayImage.appendChild(this.div);
+ var self = this;
+
+ this.listeners = [
+ google.maps.event.addListener(this, 'position_changed', function() { self.draw(); }),
+ google.maps.event.addListener(this, 'text_changed', function() { self.draw(); }),
+ google.maps.event.addListener(this, 'zindex_changed', function() { self.draw(); })
+ ];
+ }
+
+ // Marker Label onRemove
+ onRemove() {
+ this.div.parentNode.removeChild(this.div);
+
+ for (var i = 0, I = this.listeners.length; i < I; ++i) {
+ google.maps.event.removeListener(this.listeners[i]);
+ }
+ }
+
+ // Implement draw
+ draw() {
+ var projection = this.getProjection();
+ var position = projection.fromLatLngToDivPixel(this.get('position'));
+ var div = this.div;
+
+ this.div.innerHTML = this.get('text').toString();
+
+ div.style.zIndex = this.get('zIndex'); // Allow label to overlay marker
+ div.style.position = 'absolute';
+ div.style.display = 'block';
+ div.style.left = (position.x - (div.offsetWidth / 2) + 12) + 'px';
+ div.style.top = (position.y - (div.offsetHeight/2) - 24) + 'px';
+ }
+
+ set position(value) {
+ this.latlng = value;
+ }
+
+ get position() {
+ return this.latlng;
+ }
+}
+
+export default MarkerLabel;
diff --git a/addon/utils/marker.js b/addon/utils/marker.js
new file mode 100644
index 0000000..bc60941
--- /dev/null
+++ b/addon/utils/marker.js
@@ -0,0 +1,25 @@
+import MarkerLabel from './marker-label';
+
+class Marker extends google.maps.OverlayView {
+ constructor(options) {
+ super(...arguments);
+
+ this.icon = options.icon;
+
+ if (options.map_icon_label) {
+ this.MarkerLabel = new MarkerLabel({
+ position: options.position,
+ map: this.map,
+ marker: this,
+ text: options.map_icon_label
+ });
+ }
+ }
+
+ // Custom Marker SetMap
+ setMap() {
+ (this.MarkerLabel) && this.MarkerLabel.setMap.apply(this.MarkerLabel, arguments);
+ }
+}
+
+export default Marker;
diff --git a/addon/utils/tools.js b/addon/utils/tools.js
index 955d91e..5da8ce9 100644
--- a/addon/utils/tools.js
+++ b/addon/utils/tools.js
@@ -19,7 +19,66 @@ export default {
id: 'marker',
dataId: 'Point',
name: 'Marker',
- title: 'Marker Tool'
+ title: 'Marker Tool',
+ options: [
+ { name: 'Marker', type: 'Marker', id: 'marker', display: 'marker.display' },
+ { name: 'Icon', type: 'icon', id: 'icon', display: 'icon.display' },
+ { name: 'Color', type: 'color', id: 'style.color' },
+ ],
+ style: {
+ color: '#374046',
+ },
+ icons: [{
+ id: 'default',
+ display: 'Default'
+ }, {
+ id: 'grade',
+ display: 'Grade'
+ }, {
+ id: 'help',
+ display: 'Help'
+ }, {
+ id: 'favorite',
+ display: 'Favorite'
+ }, {
+ id: 'check_circle',
+ display: 'Check Circle'
+ }, {
+ id: 'lens',
+ display: 'Lens'
+ }, {
+ id: 'filter_vintage',
+ display: 'Filter Vintage'
+ }, {
+ id: 'photo_camera',
+ display: 'Photo Camera'
+ }, {
+ id: 'place',
+ display: 'Place'
+ }],
+ icon: {
+ id: 'default',
+ display: 'Default'
+ },
+
+ markers: [{
+ id: 'default',
+ display: 'Default',
+ }, {
+ id: 'pin',
+ display: 'Pin',
+ path: 'M0-48c-9.8 0-17.7 7.8-17.7 17.4 0 15.5 17.7 30.6 17.7 30.6s17.7-15.4 17.7-30.6c0-9.6-7.9-17.4-17.7-17.4z',
+ pathDropdown: 'M24 0c-9.8 0-17.7 7.8-17.7 17.4 0 15.5 17.7 30.6 17.7 30.6s17.7-15.4 17.7-30.6c0-9.6-7.9-17.4-17.7-17.4z'
+ }, {
+ id: 'squarePin',
+ display: 'Square Pin',
+ path: 'M22-48h-44v43h16l6 5 6-5h16z',
+ pathDropdown: 'M45.5 0h-43v43h16.2l5.9 5 5.8-5h15.1z'
+ }],
+ marker: {
+ id: 'default',
+ display: 'Default',
+ }
},
polyline: {
id: 'polyline',
diff --git a/app/styles/app.less b/app/styles/app.less
new file mode 100644
index 0000000..a5379e8
--- /dev/null
+++ b/app/styles/app.less
@@ -0,0 +1,4 @@
+
+@import "ember-bootstrap/bootstrap";
+
+@import "ember-power-select";
diff --git a/package.json b/package.json
index c1e0f59..5827e26 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"ember-uuid": "1.0.0"
},
"devDependencies": {
+ "bootstrap": "3.3.7",
"broccoli-asset-rev": "^2.4.5",
"broccoli-merge-trees": "^1.2.1",
"broccoli-static-compiler": "^0.2.1",
@@ -51,6 +52,7 @@
"ember-disable-prototype-extensions": "^1.1.0",
"ember-export-application-global": "^1.0.5",
"ember-load-initializers": "^0.6.3",
+ "ember-power-select": "1.8.2",
"ember-resolver": "^2.0.3",
"loader.js": "^4.0.10"
},
diff --git a/public/images/ic_person_pin_black_24px.svg b/public/images/ic_person_pin_black_24px.svg
new file mode 100644
index 0000000..0cf5662
--- /dev/null
+++ b/public/images/ic_person_pin_black_24px.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/public/images/ic_person_pin_circle_black_24px.svg b/public/images/ic_person_pin_circle_black_24px.svg
new file mode 100644
index 0000000..f1ab0e0
--- /dev/null
+++ b/public/images/ic_person_pin_circle_black_24px.svg
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/public/images/ic_place_black_24px.svg b/public/images/ic_place_black_24px.svg
new file mode 100644
index 0000000..d7844b2
--- /dev/null
+++ b/public/images/ic_place_black_24px.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/vendor/google-maps-markup/styles.css b/vendor/google-maps-markup/styles.css
index 7a9e6bf..3fd8500 100644
--- a/vendor/google-maps-markup/styles.css
+++ b/vendor/google-maps-markup/styles.css
@@ -55,3 +55,63 @@
.google-maps-markup-map-label:placeholder-shown { /* Standard (https://drafts.csswg.org/selectors-4/#placeholder) */
color: #444;
}
+
+.drop_down .ember-power-select-trigger{
+ width: 200px;
+}
+
+@font-face {
+ font-family: 'Material Icons';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Material Icons'), local('MaterialIcons-Regular'), url(https://fonts.gstatic.com/s/materialicons/v22/2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2) format('woff2');
+}
+
+.material-icons {
+ font-family: 'Material Icons';
+ font-weight: normal;
+ font-style: normal;
+ font-size: 24px;
+ width: 48px;
+ color: #FFFFFF;
+ letter-spacing: normal;
+ text-transform: none;
+ display: inline-block;
+ white-space: nowrap;
+ word-wrap: normal;
+ direction: ltr;
+ -moz-font-feature-settings: 'liga';
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.ember-power-select-option i.material-icons,
+.ember-power-select-selected-item i.material-icons {
+ color: #444444;
+ font-size: 15px;
+}
+
+.ember-power-select-selected-item, .ember-power-select-option{
+ display: flex;
+ align-items: center;
+}
+.ember-power-select-selected-item .material-icons, .ember-power-select-option .material-icons,.ember-power-select-option svg{
+ margin-left: 8px;
+}
+
+.ember-power-select-option[aria-current="true"]:hover i.material-icons {
+ color: #FFFFFF;
+}
+
+.ember-power-select-selected-item svg {
+ margin-left: 8px;
+}
+
+.ember-power-select-selected-item svg path,.ember-power-select-option svg path {
+ fill: #444444;
+}
+
+.ember-power-select-option:hover svg path {
+ fill: #FFFFFF;
+}
+
+