Javascript 如何在AngularJS中建模Snap.svg映射?

Javascript 如何在AngularJS中建模Snap.svg映射?,javascript,angularjs,svg,coffeescript,snap.svg,Javascript,Angularjs,Svg,Coffeescript,Snap.svg,我正在为一个在线棋盘游戏制作一个网络界面。我想加载Snap.svg映射,即异步加载 加载后,我想将手表添加到scope的属性,并根据属性(对象)向地图添加一些颜色。我的代码基本上是这样的: .controller('GameCtrl', [ '$scope' '$routeParams' 'GameService' ( $scope $routeParams GameService ) -> $scope.game = GameServi

我正在为一个在线棋盘游戏制作一个网络界面。我想加载Snap.svg映射,即异步加载

加载后,我想将手表添加到scope的属性,并根据属性(对象)向地图添加一些颜色。我的代码基本上是这样的:

.controller('GameCtrl', [
  '$scope'
  '$routeParams'
  'GameService'
  (
    $scope
    $routeParams
    GameService
  ) ->
    $scope.game = GameService.get($routeParams.gameId)

    $scope.map = Snap("#map")
    Snap.load("img/classical.svg", (data) ->
      console.log "Loaded map!"
      data.select("#provinces").attr
        style: ""
      provinces = data.selectAll("#provinces path")
      for province in provinces
        province.attr
          style: ""
          fill: "#FFFFFF"
          "fill-opacity": "0"
      $scope.map.append(data)

      deregisterWatch = $scope.$watch('game', ->
        console.debug "Game loaded!", $scope.game.data.Id

        for provinceName,unit of $scope.game.data.Phase.Units
          provinceName = provinceName.replace '/', '-'

          province = $scope.map.select("##{provinceName}")

          province.attr
            style: ""
            fill: powers[unit.Nation].colour
            "fill-opacity": "0.8"

          deregisterWatch()
      )

    )

])
现在的问题是,我想将地图移动到它自己的“类”或文件中,但它必须知道
$scope
,才能在加载后设置手表

我的第一个天真的方法是提取地图,然后进入范围:

define([
  'snap'
], (
  Snap
) ->
  'use strict'

  Map = ($scope, selector, svgPath) ->

    that = {}
    that.provinces = {}

    ...

    that.snap = Snap(selector)
    Snap.load(svgPath, (data) ->
      console.log "Loaded map in Map!"

      data.select("#provinces").attr
        style: ""
      provinces = data.selectAll("#provinces path")
      for province in provinces

        that.provinces[province.attr("id")] = province

        province.attr
          style: ""
          fill: "#FFFFFF"
          "fill-opacity": "0"
      that.snap.append(data)

      deregisterWatch = $scope.$watch('game', ->
        console.debug "Game loaded!", $scope.game.data.Id

        for provinceName,unit of $scope.game.data.Phase.Units
          provinceName = provinceName.replace '/', '-'

          that.colourProvince(provinceName, that.powerColors[unit.Nation].colour)

          deregisterWatch()
      )
    )

    that.colourProvince = (abbr, colour) ->
      ...

    return that

  return Map
)

但我认为必须有一个更具角度的方法来做到这一点。我是否应该作出指示?还有其他建议吗?

< P>你应该考虑写一个指示。 指令旨在封装可重用组件,尤其是图形组件

define [
  'app'  # or use any other way to get to your Angular module.
  'snap'
], (app, Snap) ->

  app.directive 'awesomeMap', ->
    # directive template: will be injected into controller ($element variable)
    template: "<svg></svg>"
    # will remplace hosting element
    replace: true
    # applicable as element and attribute
    restrict: 'EA'
    # here the "parameters" of your directive: can be parsed from HTML, or bound to parent scope (my example).
    scope:
      svgPath: '=?path'
    # controller
    controller: AwesomeMap

  class AwesomeMap

    # Controller dependencies: scope and HTML element
    @$inject: ['$scope', '$element']

    # Controller constructor: bind methods and attributes to current scope
    #
    # @param scope [Object] directive scope
    # @param element [Object] root element's HTML (angular.element)
    constructor: (@scope, element) -
      @snap = Snap(element[0])
      Snap.load(@scope.svgPath, (data) ->
        console.log "Loaded map in Map!">
        # do your stuff here !
定义[
“应用程序”#或使用任何其他方式进入角度模块。
“啪”
],(应用程序,快照)->
app.directive'awesomeMap',->
#指令模板:将被注入控制器($element变量)
模板:“”
#将重新放置宿主元素
替换:正确
#可作为元素和属性使用
限制:“EA”
#这里是指令的“参数”:可以从HTML解析,或者绑定到父范围(我的示例)。
范围:
svgPath:“=?路径”
#控制器
控制器:AwesomeMap
类星体图
#控制器依赖项:范围和HTML元素
@$inject:['$scope','$element']
#控制器构造函数:将方法和属性绑定到当前范围
#
#@param scope[Object]指令作用域
#@param-element[Object]根元素的HTML(angular.element)
构造函数:(@scope,element)-
@捕捉=捕捉(元素[0])
Snap.load(@scope.svgPath,(数据)->
console.log“地图中加载的地图!”>
#在这里做你的事!
您的指令需要在Angular的模块初始化之后加载(不要忘记在某个地方需要它),您只需要在HTML中使用它

<div data-ng-controller="AParentScope">
  My awesome map <awsome-map data-path="scopeAttribute"></awsome-map>

我很棒的地图

(与Angular一起使用CoffeeScript课程是一项挑战,我很高兴看到其他人在尝试:)

谢谢!我自己也做了类似的事情。顺便说一句,这个组件根本不会被重用,但我想指令也是一种很好的语义封装方式,对吗?是的,这是我的观点。我为与渲染相关的每个语义单元创建一个指令,即使它在我的程序中只使用过一次。有时,它被证明可以在不同的应用程序中重用:)