diff options
| -rw-r--r-- | Gemfile.lock | 22 | ||||
| -rw-r--r-- | app/assets/stylesheets/OpenLayers/custom.sass | 21 | ||||
| -rw-r--r-- | app/helpers/routes_helper.rb | 8 | ||||
| -rw-r--r-- | app/javascript/helpers/routes_map.coffee | 157 | ||||
| -rw-r--r-- | app/javascript/packs/referential_lines/show.js | 10 | ||||
| -rw-r--r-- | app/javascript/packs/routes/show.js | 123 | ||||
| -rw-r--r-- | app/javascript/routes/components/StopPointList.js | 4 | ||||
| -rw-r--r-- | app/views/referential_lines/show.html.slim | 8 | ||||
| -rw-r--r-- | config/webpack/environment.js | 2 | ||||
| -rw-r--r-- | config/webpack/loaders/coffee.js | 6 | ||||
| -rw-r--r-- | package.json | 3 | ||||
| -rw-r--r-- | yarn.lock | 12 | 
12 files changed, 238 insertions, 138 deletions
| diff --git a/Gemfile.lock b/Gemfile.lock index 09ef00f94..f4dfe1bf7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -156,6 +156,7 @@ GEM        sort_alphabetical (~> 1.0)      crack (0.4.3)        safe_yaml (~> 1.0.0) +    crass (1.0.3)      cucumber (2.4.0)        builder (>= 2.1.2)        cucumber-core (~> 1.5.0) @@ -265,7 +266,7 @@ GEM      htmlbeautifier (1.3.1)      httparty (0.14.0)        multi_xml (>= 0.5.2) -    i18n (0.9.0) +    i18n (0.9.3)        concurrent-ruby (~> 1.0)      i18n-tasks (0.9.15)        activesupport (>= 4.0.2) @@ -302,7 +303,8 @@ GEM        thor        with_env (> 1.0)        xml-simple -    loofah (2.0.3) +    loofah (2.1.1) +      crass (~> 1.0.2)        nokogiri (>= 1.5.9)      mail (2.6.4)        mime-types (>= 1.16, < 4) @@ -313,7 +315,7 @@ GEM      mime-types-data (3.2016.0521)      mimemagic (0.3.2)      mini_portile2 (2.3.0) -    minitest (5.10.3) +    minitest (5.11.2)      money (6.10.1)        i18n (>= 0.6.4, < 1.0)      multi_json (1.12.1) @@ -368,7 +370,7 @@ GEM        rack      rack-protection (1.5.3)        rack -    rack-proxy (0.6.2) +    rack-proxy (0.6.3)        rack      rack-test (0.6.3)        rack (>= 1.0) @@ -396,8 +398,8 @@ GEM        rails-assets-jquery (>= 1.0.0)      rails-deprecated_sanitizer (1.0.3)        activesupport (>= 4.2.0.alpha) -    rails-dom-testing (1.0.8) -      activesupport (>= 4.2.0.beta, < 5.0) +    rails-dom-testing (1.0.9) +      activesupport (>= 4.2.0, < 5.0)        nokogiri (~> 1.6)        rails-deprecated_sanitizer (>= 1.0.1)      rails-erd (1.5.2) @@ -419,7 +421,7 @@ GEM        thor (>= 0.18.1, < 2.0)      rainbow (2.2.2)        rake -    rake (12.0.0) +    rake (12.3.0)      ransack (1.8.3)        actionpack (>= 3.0)        activerecord (>= 3.0) @@ -541,7 +543,7 @@ GEM      therubyracer (0.12.3)        libv8 (~> 3.16.14.15)        ref -    thor (0.19.4) +    thor (0.20.0)      thread (0.2.2)      thread_safe (0.3.6)      tilt (1.4.1) @@ -553,7 +555,7 @@ GEM        json (>= 1.8, < 3.0)        parser (>= 2.3.0.7)        rainbow (>= 1.99.1, < 3.0) -    tzinfo (1.2.3) +    tzinfo (1.2.4)        thread_safe (~> 0.1)      uglifier (2.7.2)        execjs (>= 0.3.0) @@ -566,7 +568,7 @@ GEM        addressable (>= 2.3.6)        crack (>= 0.3.2)        hashdiff -    webpacker (3.0.2) +    webpacker (3.2.1)        activesupport (>= 4.2)        rack-proxy (>= 0.6.1)        railties (>= 4.2) diff --git a/app/assets/stylesheets/OpenLayers/custom.sass b/app/assets/stylesheets/OpenLayers/custom.sass index 7a5b4baf1..5a3612f99 100644 --- a/app/assets/stylesheets/OpenLayers/custom.sass +++ b/app/assets/stylesheets/OpenLayers/custom.sass @@ -2,6 +2,27 @@    .list-group-item &      margin-top: 15px +  .routes-labels +    padding: 0 +    display: flex +    justify-content: space-between +    flex-wrap: wrap +    margin: 5px -5px +    li +      list-style-type: none +      flex: 1 0 25% +      border: 1px solid $lightgrey +      padding: 5px +      margin: 5px +      border-radius: 5px +      cursor: pointer +      color: $blue +      white-space: nowrap +      max-width: 33% + +      &:hover +        background: $orange +        color: white    .ol-scale-line      background-color: transparent diff --git a/app/helpers/routes_helper.rb b/app/helpers/routes_helper.rb index 4bffa99d4..61714a066 100644 --- a/app/helpers/routes_helper.rb +++ b/app/helpers/routes_helper.rb @@ -19,13 +19,15 @@ module RoutesHelper      css    end -  def route_json_for_edit(route) -    route.stop_points.includes(:stop_area).order(:position).map do |stop_point| +  def route_json_for_edit(route, serialize: true) +    data = route.stop_points.includes(:stop_area).order(:position).map do |stop_point|        stop_area_attributes = stop_point.stop_area.attributes.slice("name","city_name", "zip_code", "registration_number", "longitude", "latitude", "area_type", "comment")        stop_area_attributes["short_name"] = truncate(stop_area_attributes["name"], :length => 30) || ""        stop_point_attributes = stop_point.attributes.slice("for_boarding","for_alighting")        stop_area_attributes.merge(stop_point_attributes).merge(stoppoint_id: stop_point.id, stoparea_id: stop_point.stop_area.id).merge(user_objectid: stop_point.stop_area.user_objectid) -    end.to_json +    end +    data = data.to_json if serialize +    data    end  end diff --git a/app/javascript/helpers/routes_map.coffee b/app/javascript/helpers/routes_map.coffee new file mode 100644 index 000000000..85def1390 --- /dev/null +++ b/app/javascript/helpers/routes_map.coffee @@ -0,0 +1,157 @@ +class RoutesMap +  constructor: (@target)-> +    @initMap() +    @area = [] +    @seenStopIds = [] +    @routes = {} + +  initMap: -> +    @map = new ol.Map +      target: @target, +      layers:   [ new ol.layer.Tile(source: new ol.source.OSM()) ] +      controls: [ new ol.control.ScaleLine(), new ol.control.Zoom(), new ol.control.ZoomSlider() ], +      interactions: ol.interaction.defaults(zoom: true) +      view: new ol.View() + +  addRoutes: (routes)-> +    for route in routes +      @addRoute route + +  addRoute: (route)-> +    geoColPts = [] +    geoColLns = [] +    @routes[route.id] = route if route.id +    stops = route.stops || route +    geoColEdges = [ +      new ol.Feature({ +        geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stops[0].longitude), parseFloat(stops[0].latitude)])) +      }), +      new ol.Feature({ +        geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stops[stops.length - 1].longitude), parseFloat(stops[stops.length - 1].latitude)])) +      }) +    ] +    stops.forEach (stop, i) => +      if i < stops.length - 1 +        geoColLns.push new ol.Feature +          geometry: new ol.geom.LineString([ +            ol.proj.fromLonLat([parseFloat(stops[i].longitude), parseFloat(stops[i].latitude)]), +            ol.proj.fromLonLat([parseFloat(stops[i + 1].longitude), parseFloat(stops[i + 1].latitude)]) +          ]) + +      geoColPts.push(new ol.Feature({ +        geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)])) +      })) +      unless @seenStopIds.indexOf(stop.stoparea_id) > 0 +        @area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)] +        @seenStopIds.push stop.stoparea_id + +    vectorPtsLayer = new ol.layer.Vector({ +      source: new ol.source.Vector({ +        features: geoColPts +      }), +      style: @defaultStyles(), +      zIndex: 2 +    }) +    route.vectorPtsLayer = vectorPtsLayer if route.id +    vectorEdgesLayer = new ol.layer.Vector({ +      source: new ol.source.Vector({ +        features: geoColEdges +      }), +      style: @edgeStyles(), +      zIndex: 3 +    }) +    route.vectorEdgesLayer = vectorEdgesLayer if route.id +    vectorLnsLayer = new ol.layer.Vector({ +      source: new ol.source.Vector({ +        features: geoColLns +      }), +      style: [@lineStyle()], +      zIndex: 1 +    }) +    route.vectorLnsLayer = vectorLnsLayer if route.id +    @map.addLayer vectorPtsLayer +    @map.addLayer vectorEdgesLayer +    @map.addLayer vectorLnsLayer + +  lineStyle: (highlighted=false)-> +    new ol.style.Style +      stroke: new ol.style.Stroke +        color: if highlighted then "#ed7f00" else '#007fbb' +        width: 3 + +  edgeStyles: (highlighted=false)-> +    new ol.style.Style +      image: new ol.style.Circle +        radius: 5 +        stroke: new ol.style.Stroke +          color: if highlighted then "#ed7f00" else '#007fbb' +          width: 2 +        fill: new ol.style.Fill +          color: if highlighted then "#ed7f00" else '#007fbb' +          width: 2 + +  defaultStyles: (highlighted=false)-> +    new ol.style.Style +      image: new ol.style.Circle +        radius: 4 +        stroke: new ol.style.Stroke +          color: if highlighted then "#ed7f00" else '#007fbb' +          width: 2 +        fill: new ol.style.Fill +          color: '#ffffff' +          width: 2 + +  addRoutesLabels: -> +    labelsContainer = $("<ul class='routes-labels'></ul>") +    labelsContainer.appendTo $("##{@target}") +    @vectorPtsLayer = null +    @vectorEdgesLayer = null +    @vectorLnsLayer = null +    Object.keys(@routes).forEach (id)=> +      route = @routes[id] +      label = $("<li>#{route.name}</ul>") +      label.appendTo labelsContainer +      label.mouseleave => +        route.vectorPtsLayer.setStyle @defaultStyles(false) +        route.vectorEdgesLayer.setStyle @edgeStyles(false) +        route.vectorLnsLayer.setStyle @lineStyle(false) +        route.vectorPtsLayer.setZIndex 2 +        route.vectorEdgesLayer.setZIndex 3 +        route.vectorLnsLayer.setZIndex 1 +        @fitZoom() +      label.mouseenter => +        route.vectorPtsLayer.setStyle @defaultStyles(true) +        route.vectorEdgesLayer.setStyle @edgeStyles(true) +        route.vectorLnsLayer.setStyle @lineStyle(true) +        route.vectorPtsLayer.setZIndex 11 +        route.vectorEdgesLayer.setZIndex 12 +        route.vectorLnsLayer.setZIndex 10 +        @fitZoom(route) + +  fitZoom: (route)-> +    if route +      area = [] +      route.stops.forEach (stop, i) => +        area.push [parseFloat(stop.longitude), parseFloat(stop.latitude)] +    else +      area = @area +    boundaries = ol.extent.applyTransform( +      ol.extent.boundingExtent(area), ol.proj.getTransform('EPSG:4326', 'EPSG:3857') +    ) +    @map.getView().fit boundaries, @map.getSize() +    tooCloseToBounds = false +    mapBoundaries = @map.getView().calculateExtent @map.getSize() +    mapWidth = mapBoundaries[2] - mapBoundaries[0] +    mapHeight = mapBoundaries[3] - mapBoundaries[1] +    marginSize = 0.1 +    heightMargin = marginSize * mapHeight +    widthMargin = marginSize * mapWidth +    tooCloseToBounds = tooCloseToBounds || (boundaries[0] - mapBoundaries[0]) < widthMargin +    tooCloseToBounds = tooCloseToBounds || (mapBoundaries[2] - boundaries[2]) < widthMargin +    tooCloseToBounds = tooCloseToBounds || (boundaries[1] - mapBoundaries[1]) < heightMargin +    tooCloseToBounds = tooCloseToBounds || (mapBoundaries[3] - boundaries[3]) < heightMargin +    if tooCloseToBounds +      @map.getView().setZoom(@map.getView().getZoom() - 1) + + +export default RoutesMap diff --git a/app/javascript/packs/referential_lines/show.js b/app/javascript/packs/referential_lines/show.js new file mode 100644 index 000000000..99c5072ef --- /dev/null +++ b/app/javascript/packs/referential_lines/show.js @@ -0,0 +1,10 @@ +import clone from '../../helpers/clone' +import RoutesMap from '../../helpers/routes_map' + +let routes = clone(window, "routes", true) +routes = JSON.parse(decodeURIComponent(routes)) + +var map = new RoutesMap('routes_map') +map.addRoutes(routes) +map.addRoutesLabels() +map.fitZoom() diff --git a/app/javascript/packs/routes/show.js b/app/javascript/packs/routes/show.js index 71777c379..c20de0800 100644 --- a/app/javascript/packs/routes/show.js +++ b/app/javascript/packs/routes/show.js @@ -1,121 +1,8 @@  import clone from '../../helpers/clone' +import RoutesMap from '../../helpers/routes_map' +  let route = clone(window, "route", true)  route = JSON.parse(decodeURIComponent(route)) - -const geoColPts = [] -const geoColLns = [] -const area = [] -const geoColEdges = [ -  new ol.Feature({ -    geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(route[0].longitude), parseFloat(route[0].latitude)])) -  }), -  new ol.Feature({ -    geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(route[route.length - 1].longitude), parseFloat(route[route.length - 1].latitude)])) -  }) -] -route.forEach(function (stop, i) { -  if (i < route.length - 1) { -    geoColLns.push(new ol.Feature({ -      geometry: new ol.geom.LineString([ -        ol.proj.fromLonLat([parseFloat(route[i].longitude), parseFloat(route[i].latitude)]), -        ol.proj.fromLonLat([parseFloat(route[i + 1].longitude), parseFloat(route[i + 1].latitude)]) -      ]) -    })) -  } -  geoColPts.push(new ol.Feature({ -    geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(stop.longitude), parseFloat(stop.latitude)])) -  })) -  area.push([parseFloat(stop.longitude), parseFloat(stop.latitude)]) -}) -var edgeStyles = new ol.style.Style({ -  image: new ol.style.Circle(({ -    radius: 5, -    stroke: new ol.style.Stroke({ -      color: '#007fbb', -      width: 2 -    }), -    fill: new ol.style.Fill({ -      color: '#007fbb', -      width: 2 -    }) -  })) -}) -var defaultStyles = new ol.style.Style({ -  image: new ol.style.Circle(({ -    radius: 4, -    stroke: new ol.style.Stroke({ -      color: '#007fbb', -      width: 2 -    }), -    fill: new ol.style.Fill({ -      color: '#ffffff', -      width: 2 -    }) -  })) -}) -var lineStyle = new ol.style.Style({ -  stroke: new ol.style.Stroke({ -    color: '#007fbb', -    width: 3 -  }) -}) - -var vectorPtsLayer = new ol.layer.Vector({ -  source: new ol.source.Vector({ -    features: geoColPts -  }), -  style: defaultStyles, -  zIndex: 2 -}) -var vectorEdgesLayer = new ol.layer.Vector({ -  source: new ol.source.Vector({ -    features: geoColEdges -  }), -  style: edgeStyles, -  zIndex: 3 -}) -var vectorLnsLayer = new ol.layer.Vector({ -  source: new ol.source.Vector({ -    features: geoColLns -  }), -  style: [lineStyle], -  zIndex: 1 -}) - -var map = new ol.Map({ -  target: 'route_map', -  layers: [ -    new ol.layer.Tile({ -      source: new ol.source.OSM() -    }), -    vectorPtsLayer, -    vectorEdgesLayer, -    vectorLnsLayer -  ], -  controls: [new ol.control.ScaleLine(), new ol.control.Zoom(), new ol.control.ZoomSlider()], -  interactions: ol.interaction.defaults({ -    zoom: true -  }), -  view: new ol.View({ -    center: ol.proj.fromLonLat([parseFloat(route[0].longitude), parseFloat(route[0].latitude)]), -    zoom: 13 -  }) -}); -const boundaries = ol.extent.applyTransform( -  ol.extent.boundingExtent(area), ol.proj.getTransform('EPSG:4326', 'EPSG:3857') -) -map.getView().fit(boundaries, map.getSize()); -let tooCloseToBounds = false -const mapBoundaries = map.getView().calculateExtent(map.getSize()) -const mapWidth = mapBoundaries[2] - mapBoundaries[0] -const mapHeight = mapBoundaries[3] - mapBoundaries[1] -const marginSize = 0.1 -const heightMargin = marginSize * mapHeight -const widthMargin = marginSize * mapWidth -tooCloseToBounds = tooCloseToBounds || (boundaries[0] - mapBoundaries[0]) < widthMargin -tooCloseToBounds = tooCloseToBounds || (mapBoundaries[2] - boundaries[2]) < widthMargin -tooCloseToBounds = tooCloseToBounds || (boundaries[1] - mapBoundaries[1]) < heightMargin -tooCloseToBounds = tooCloseToBounds || (mapBoundaries[3] - boundaries[3]) < heightMargin -if(tooCloseToBounds){ -  map.getView().setZoom(map.getView().getZoom() - 1) -} +var map = new RoutesMap('route_map') +map.addRoute(route) +map.fitZoom() diff --git a/app/javascript/routes/components/StopPointList.js b/app/javascript/routes/components/StopPointList.js index 43a027084..b39fa0c9c 100644 --- a/app/javascript/routes/components/StopPointList.js +++ b/app/javascript/routes/components/StopPointList.js @@ -56,7 +56,7 @@ export default function StopPointList({ stopPoints, onDeleteClick, onMoveUpClick    )  } -StopPointList.PropTypes = { +StopPointList.propTypes = {    stopPoints: PropTypes.array.isRequired,    onDeleteClick: PropTypes.func.isRequired,    onMoveUpClick: PropTypes.func.isRequired, @@ -68,4 +68,4 @@ StopPointList.PropTypes = {  StopPointList.contextTypes = {    I18n: PropTypes.object -}
\ No newline at end of file +} diff --git a/app/views/referential_lines/show.html.slim b/app/views/referential_lines/show.html.slim index 02d605d8c..5ea0e31bb 100644 --- a/app/views/referential_lines/show.html.slim +++ b/app/views/referential_lines/show.html.slim @@ -17,7 +17,8 @@               @line.human_attribute_name(:transport_submode) => (@line.transport_submode.present? ? t("enumerize.transport_submode.#{@line.transport_submode}") : '-'),               @line.human_attribute_name(:url) => (@line.url ? @line.url : '-'),               @line.human_attribute_name(:seasonal) => (@line.seasonal? ? t('true') : t('false')),} - +      .col-lg-6.col-md-6.col-sm-12.col-xs-12 +        #routes_map.map.mb-lg      .row        .col-lg-12          .h3 = t('lines.show.routes.title') @@ -79,3 +80,8 @@            .row.mt-xs              .col-lg-12                = replacement_msg t('routes.search_no_results') + += javascript_tag do +  | window.routes = "#{URI.escape(@routes.map{|r| {name: r.name, id: r.id, stops: route_json_for_edit(r, serialize: false)}}.to_json)}" + += javascript_pack_tag 'referential_lines/show.js' diff --git a/config/webpack/environment.js b/config/webpack/environment.js index e7c879fb9..688bcbe8e 100644 --- a/config/webpack/environment.js +++ b/config/webpack/environment.js @@ -1,4 +1,5 @@  const { environment } = require('@rails/webpacker') +const coffee =  require('./loaders/coffee')  const CleanWebpackPlugin = require('clean-webpack-plugin')  let pathsToClean = [ @@ -24,4 +25,5 @@ environment.plugins.set(  //   jquery: "jquery/src/jquery",  // } +environment.loaders.append('coffee', coffee)  module.exports = environment diff --git a/config/webpack/loaders/coffee.js b/config/webpack/loaders/coffee.js new file mode 100644 index 000000000..4666716dc --- /dev/null +++ b/config/webpack/loaders/coffee.js @@ -0,0 +1,6 @@ +module.exports = { +  test: /\.coffee(\.erb)?$/, +  use: [{ +    loader: 'coffee-loader' +  }] +} diff --git a/package.json b/package.json index 80ca22f83..802a2eef7 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@      "babel-preset-react": "6.24.1",      "babelify": "8.0.0",      "bootstrap": "3", -    "coffeescript": "2.1.0", +    "coffee-loader": "^0.9.0", +    "coffeescript": "1.12.7",      "jquery": "3.2.1",      "lodash": "4.17.4",      "promise-polyfill": "7.0.0", @@ -1404,13 +1404,19 @@ code-point-at@^1.0.0:    version "1.1.0"    resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +coffee-loader@^0.9.0: +  version "0.9.0" +  resolved "https://registry.yarnpkg.com/coffee-loader/-/coffee-loader-0.9.0.tgz#6deabd336062ddc6d773da4dfd16367fc7107bd6" +  dependencies: +    loader-utils "^1.0.2" +  coffee-script@~1.10.0:    version "1.10.0"    resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.10.0.tgz#12938bcf9be1948fa006f92e0c4c9e81705108c0" -coffeescript@2.1.0: -  version "2.1.0" -  resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-2.1.0.tgz#8cb7ce12021ab9f84d8c524f54edbd6141374606" +coffeescript@1.12.7: +  version "1.12.7" +  resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-1.12.7.tgz#e57ee4c4867cf7f606bfc4a0f2d550c0981ddd27"  color-convert@^1.3.0, color-convert@^1.8.2, color-convert@^1.9.0:    version "1.9.0" | 
