<commit_before><template>
  <div>
    <Radio-group class="radio-group" :model.sync="view" type="button" >
      <Radio value="散点图"></Radio>
      <Radio value="轨迹图"></Radio>
      <Radio value="热区图"></Radio>
    </Radio-group>
  </div>
</template>


<script>
import mapboxgl from 'mapbox-gl/dist/mapbox-gl'
import groupBy from 'lodash/groupBy'
import moment from 'moment'

let map

export default {
  props: {
    accessToken: {
      type: String,
      required: true
    },
    options: {
      type: Object,
      required: true,
      validator (value) {
        return !!value.style
      }
    }
  },

  data () {
    return {
      view: '散点图'
    }
  },

  ready () {
    mapboxgl.accessToken = this.accessToken
    this.options.container = this.$el
    map = new mapboxgl.Map(this.options)
    map.addControl(new mapboxgl.NavigationControl(), 'top-left')
    map.on('load', () => {
      this.addScatterSource(this.$store.state.locations)
      this.addScatterLayer()
      this.addTrackSource(this.$store.state.locations)
      this.addTrackLayer()
      this.addHeatSource(this.$store.state.locations)
      this.addHeatLayer()
    })
  },

  watch: {
    view (value) {
      switch (value) {
        case '散点图':
          map.setLayoutProperty('scatter-layer', 'visibility', 'visible')
          map.setLayoutProperty('track-layer', 'visibility', 'none')
          // map.setLayoutProperty('heat-layer', 'visibility', 'none')
          break
        case '轨迹图':
          map.setLayoutProperty('scatter-layer', 'visibility', 'none')
          map.setLayoutProperty('track-layer', 'visibility', 'visible')
          // map.setLayoutProperty('heat-layer', 'visibility', 'none')
          break
        case '热区图':
          map.setLayoutProperty('scatter-layer', 'visibility', 'none')
          map.setLayoutProperty('track-layer', 'visibility', 'none')
          // map.setLayoutProperty('heat-layer', 'visibility', 'visible')
          break
      }
    },

    '$store.state.locations' (locations) {
      this.addScatterSource(locations)
      this.addTrackSource(locations)
      this.addHeatSource(locations)
    }
  },

  methods: {
    addScatterSource (locations) {
      const data = {
        type: 'FeatureCollection',
        features: []
      }

      locations.forEach((location) => {
        data.features.push({
          type: 'Feature',
          geometry: {
            type: 'Point',
            coordinates: [location.lng, location.lat]
          },
          properties: {
            deviceId: location.deviceId,
            createdAt: location.createdAt,
            updatedAt: location.updatedAt
          }
        })
      })

      const source = map.getSource('scatter-source')
      if (source) {
        source.setData(data)
      } else {
        map.addSource('scatter-source', {
          type: 'geojson',
          data: data
        })
      }
    },

    addScatterLayer () {
      const layer = map.getLayer('scatter-layer')
      if (!layer) {
        map.addLayer({
          id: 'scatter-layer',
          type: 'circle',
          source: 'scatter-source',
          layout: {
            visibility: this.view === '散点图' ? 'visible' : 'none'
          },
          paint: {
            'circle-radius': 5,
            'circle-color': '#0061ff',
            'circle-stroke-color': '#fff',
            'circle-stroke-width': 1
          }
        }, 'wall-base')
      }

      const popup = new mapboxgl.Popup({
        closeButton: false,
        closeOnClick: false
      })

      map.on('mousemove', function (e) {
        const features = map.queryRenderedFeatures(e.point, {layers: ['scatter-layer']})
        map.getCanvas().style.cursor = (features.length) ? 'pointer' : ''

        if (!features.length) {
          popup.remove()
          return
        }

        popup.setLngLat(e.lngLat)
          .setHTML(features[0].properties.deviceId)
          .addTo(map)
      })
    },

    addTrackSource (locations) {
      const groupedLocations = groupBy(locations, location => {
        return moment(location.createdAt).format('YYYY-MM-DD')
      })

      Object.keys(groupedLocations).forEach(function (key) {
        groupedLocations[key] = groupBy(groupedLocations[key], location => {
          return location.deviceId
        })
      })

      const tracks = []
      Object.keys(groupedLocations).forEach(function (key1) {
        Object.keys(groupedLocations[key1]).forEach(function (key2) {
          tracks.push({
            date: key1,
            deviceId: key2,
            locations: groupedLocations[key1][key2].sort((loc1, loc2) => {
              return new Date(loc1) - new Date(loc2)
            })
          })
        })
      })

      const data = {
        type: 'FeatureCollection',
        features: []
      }<commit_msg>add tracklayer<commit_after><template>
  <div>
    <Radio-group class="radio-group" :model.sync="view" type="button" >
      <Radio value="散点图"></Radio>
      <Radio value="轨迹图"></Radio>
      <Radio value="热区图"></Radio>
    </Radio-group>
  </div>
</template>


<script>
import mapboxgl from 'mapbox-gl/dist/mapbox-gl'
import groupBy from 'lodash/groupBy'
import moment from 'moment'

let map

export default {
  props: {
    accessToken: {
      type: String,
      required: true
    },
    options: {
      type: Object,
      required: true,
      validator (value) {
        return !!value.style
      }
    }
  },

  data () {
    return {
      view: '散点图'
    }
  },

  ready () {
    mapboxgl.accessToken = this.accessToken
    this.options.container = this.$el
    map = new mapboxgl.Map(this.options)
    map.addControl(new mapboxgl.NavigationControl(), 'top-left')
    map.on('load', () => {
      this.addScatterSource(this.$store.state.locations)
      this.addScatterLayer()
      this.addTrackSource(this.$store.state.locations)
      this.addTrackLayer()
      this.addHeatSource(this.$store.state.locations)
      this.addHeatLayer()
    })
  },

  watch: {
    view (value) {
      switch (value) {
        case '散点图':
          map.setLayoutProperty('scatter-layer', 'visibility', 'visible')
          map.setLayoutProperty('track-layer', 'visibility', 'none')
          // map.setLayoutProperty('heat-layer', 'visibility', 'none')
          break
        case '轨迹图':
          map.setLayoutProperty('scatter-layer', 'visibility', 'none')
          map.setLayoutProperty('track-layer', 'visibility', 'visible')
          // map.setLayoutProperty('heat-layer', 'visibility', 'none')
          break
        case '热区图':
          map.setLayoutProperty('scatter-layer', 'visibility', 'none')
          map.setLayoutProperty('track-layer', 'visibility', 'none')
          // map.setLayoutProperty('heat-layer', 'visibility', 'visible')
          break
      }
    },

    '$store.state.locations' (locations) {
      this.addScatterSource(locations)
      this.addTrackSource(locations)
      this.addHeatSource(locations)
    }
  },

  methods: {
    addScatterSource (locations) {
      const data = {
        type: 'FeatureCollection',
        features: []
      }

      locations.forEach((location) => {
        data.features.push({
          type: 'Feature',
          geometry: {
            type: 'Point',
            coordinates: [location.lng, location.lat]
          },
          properties: {
            deviceId: location.deviceId,
            createdAt: location.createdAt,
            updatedAt: location.updatedAt
          }
        })
      })

      const source = map.getSource('scatter-source')
      if (source) {
        source.setData(data)
      } else {
        map.addSource('scatter-source', {
          type: 'geojson',
          data: data
        })
      }
    },

    addScatterLayer () {
      const layer = map.getLayer('scatter-layer')
      if (!layer) {
        map.addLayer({
          id: 'scatter-layer',
          type: 'circle',
          source: 'scatter-source',
          layout: {
            visibility: this.view === '散点图' ? 'visible' : 'none'
          },
          paint: {
            'circle-radius': 5,
            'circle-color': '#0061ff',
            'circle-stroke-color': '#fff',
            'circle-stroke-width': 1
          }
        }, 'wall-base')
      }

      const popup = new mapboxgl.Popup({
        closeButton: false,
        closeOnClick: false
      })

      map.on('mousemove', function (e) {
        const features = map.queryRenderedFeatures(e.point, {layers: ['scatter-layer']})
        map.getCanvas().style.cursor = (features.length) ? 'pointer' : ''

        if (!features.length) {
          popup.remove()
          return
        }

        popup.setLngLat(e.lngLat)
          .setHTML(features[0].properties.deviceId)
          .addTo(map)
      })
    },

    addTrackSource (locations) {
      const groupedLocations = groupBy(locations, location => {
        return moment(location.createdAt).format('YYYY-MM-DD')
      })

      Object.keys(groupedLocations).forEach(function (key) {
        groupedLocations[key] = groupBy(groupedLocations[key], location => {
          return location.deviceId
        })
      })

      const tracks = []
      Object.keys(groupedLocations).forEach(function (key1) {
        Object.keys(groupedLocations[key1]).forEach(function (key2) {
          tracks.push({
            date: key1,
            deviceId: key2,
            locations: groupedLocations[key1][key2].sort((loc1, loc2) => {
              return Date.parse(loc1.createdAt) - Date.parse(loc2.createdAt)
            })
          })
        })
      })

      const data = {
        type: 'FeatureCollection',
        features: []
      }
{'fraction_non_alphanumeric': 0.1424578113676364, 'fraction_numerical': 0.0037270939020602545, 'mean_word_length': 1.988861386138614, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6163963', 'n_tokens_mistral': 2977, 'n_tokens_neox': 2887, 'n_words': 491}