読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

Google MapsのカスタムInfoWindow

CustomInfoWindowのインスタンスに対応するDOMはinfo-windowクラスを持つようになりますので、CSSで自由にデザインできます。

描画位置はanchorの上です。drawを変更することで変えられます。

onAddでclickイベントの伝搬を止めています。必要に応じて他のマウスイベントも止めて下さい。
contentの中身でclickなどマウスイベントを拾う場合、jQueryのlive関数相当でDOMが存在する前にあらかじめバインドすると、親要素で抑制したイベントは受けられなくなります。
DOMを用意してイベントリスナーをバインドしてからsetContentで渡すか、domreadyイベントを拾ってそこでイベントリスナーをバインドするようにしてください。
(追記: 残念なことにiOS Safariではclickが抑制されませんでした。)

class MobileInfoWindow extends google.maps.OverlayView
    constructor: (options) -> @setOptions options
    close: -> @setMap null
    getContent: -> @content
    getPosition: -> @position
    getZIndex: -> @zIndex
    open: (map, @anchor) ->
        if anchor?
            @setPosition anchor.getPosition()
            icon = @anchor.getIcon()
            markerAnchor = icon.anchor ? new google.maps.Point Math.floor(icon.size.width / 2), icon.size.height
            markerSize = @anchor.getIcon().size
            @pixelOffset = new google.maps.Size Math.floor(markerSize.width / 2) - markerAnchor.x, - markerAnchor.y, 'px', 'px'            
        @setMap map
        
    setContent: (@content) ->
        unless @element?
            @element = document.createElement 'div'
            @element.style['max-width'] = @maxWidth + 'px' if @maxWidth
            @element.className = 'info-window'
        if typeof @content is 'string'
            @element.innerHTML = @content
        else
            @element.appendChild @content
        google.maps.event.trigger this, 'content_changed'
        
    setOptions: (options) ->
        @maxWidth = options.maxWidth ? null
        @setContent options.content ? ''
        @disableAutoPan = options.disableAutoPan ? null
        @pixelOffset = options.pixelOffset ? new google.maps.Size 0, 0, 'px', 'px'
        @setPosition options.position ? null
        @setZIndex options.zIndex ? 0
        
    setPosition: (@position) ->
        google.maps.event.trigger this, 'position_changed'
        
    setZIndex: (@zIndex) ->
        @element.style['z-index'] = @zIndex.toString()
        google.maps.event.trigger this, 'zindex_changed'

    # overlayview
    onAdd: ->
        @getPanes().floatPane.appendChild @element
        @clickListener = google.maps.event.addDomListener @element, 'click', (event) ->
            event.stopPropagation();
        google.maps.event.trigger this, 'domready'

    draw: ->
        xy = @getProjection().fromLatLngToDivPixel @getPosition()
        @element.style.left = xy.x + @pixelOffset.width - @element.offsetWidth / 2 + 'px'
        @element.style.top = xy.y + @pixelOffset.height - @element.offsetHeight + 'px'

    onRemove: ->
        google.maps.event.removeListener @clickListener
        @element.parentNode.removeChild @element
        # setMapがonRemoveを呼んでonAddを呼ぶので、@elementはnullにせずに再利用すること。