Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elm:将单击事件添加到SVG元素不会';t工作–;这可能吗?_Svg_Mouseevent_Elm - Fatal编程技术网

Elm:将单击事件添加到SVG元素不会';t工作–;这可能吗?

Elm:将单击事件添加到SVG元素不会';t工作–;这可能吗?,svg,mouseevent,elm,Svg,Mouseevent,Elm,我一直在尝试向Elm中的SVG元素添加一个“click”事件,以确定鼠标单击在该元素中的相对位置 下面给出了一个代码示例,您可以尝试在上运行,以显示HTML元素上的单击事件似乎是如何按预期工作的,而不是SVG元素上的 在示例中,使用“单击”而不是Html.onClick来允许从事件中解码位置数据,如中所述 在阅读了文档和源代码之后,我希望在将“click”事件添加到SVG元素时,它的工作方式与将事件添加到HTML元素的方式相同。但是,完成此操作后,单击SVG元素不会触发事件,也不会向更新函数发送

我一直在尝试向Elm中的SVG元素添加一个“click”事件,以确定鼠标单击在该元素中的相对位置

下面给出了一个代码示例,您可以尝试在上运行,以显示HTML元素上的单击事件似乎是如何按预期工作的,而不是SVG元素上的

在示例中,使用“单击”而不是
Html.onClick
来允许从事件中解码位置数据,如中所述

在阅读了文档和源代码之后,我希望在将“click”事件添加到SVG元素时,它的工作方式与将事件添加到HTML元素的方式相同。但是,完成此操作后,单击SVG元素不会触发事件,也不会向更新函数发送任何消息

在本例中,在黑色SVG
rect
内单击应触发更新功能并更改白色
rect
的位置,但单击被忽略。这可以通过打开控制台并注意未调用
Debug.log
来确认。HTML
div
被放置在具有相同单击事件的下方,当在该
div
中注册单击时,白色的
rect
会改变位置

这是Elm中的预期行为吗?是否有任何解决方法

关于stackoverflow也有类似的问题,但这是指画布形状,据我所知,这是一个完全独立的问题(尽管我可能错了)

代码示例:
Json解码器无法工作的原因很明显,因为 系统中不存在
offsetLeft
offsetTop
事件对象

这有点令人困惑,因为这些属性是可用的 用于Html DOM的单击事件,但不用于SVG DOM。 (我的建议 在Elm中实现事件解码器需要附加临时 浏览器调试器控制台中的事件处理程序,并研究实际的事件对象。Elm的解码器无声地失败,并且很难知道解码器失败的原因 不起作用。 )

在这里,我实现了另一种方法,您可以使用
端口
获取 使用javascript的父位置(不使用任何 社区图书馆)

端口模块主显示(主)
导入Html公开(Html,div)
将Html.App作为应用程序导入
导入Html.Attributes
导入Html.Events(打开)
将Json.Decode作为Json公开(object2、object1、int、at)
导入鼠标(位置)
导入Svg(Svg、rect)
导入Svg.Attributes公开(..)
主:程序永远不会
主要=
应用程序
{init=(initmodel,getParentPos())
,视图=视图
,update=update
,订阅=订阅
}
类型别名模型=
{位置:位置
,parentPosition:Position
}
输入味精
=改变位置
|UpdateParentPosition{top:Int,left:Int}
initmodel:Model
初始模型=
{位置=位置0
,parentPosition=位置0
}
更新:Msg->Model->(Model,Cmd-Msg)
更新msg模型=
case Debug.log“msg”msg的
改变位置->
让
相对位置
(position.x-model.parentPosition.x)
(position.y-model.parentPosition.y)
in({model | position=relativepos},Cmd.none)
UpdateParentPosition{top,left}->
({model | parentPosition=Position top left},Cmd.none)
端口getParentPos:()->Cmd msg
订阅:模型->子消息
订阅模式=
parentPos UpdateParentPosition
端口parentPos:({top:Int,left:Int}->msg)->Sub msg
查看:模型->Html消息
视图模型=
分区[]
[svg
[宽度“400”
,高度“100”
,视图框“0 0 400 100”
,id“parent”
]
[rect
[onClickLocation--这应该可以工作,但不起任何作用
,宽度“400”
,高度“100”
,x“0”
,y“0”
,填写“#000”
,光标“指针”
]
[]
,rect
[宽度“50”
,高度“50”
,x(toString模型.position.x)
,y(toString model.position.y)
,填写“#fff”
]
[]
]
,分区
[onClickLocation]这很有效
,Html.Attributes.style
[(“背景色”、“白色”)
,(“边框”,“2件纯黑”)
,(“宽度”,“400px”)
,(“高度”,“100px”)
(“位置”、“绝对”)
,(“左”,“0px”)
,(“顶部”,“150像素”)
(“颜色”、“黑色”)
(“光标”、“指针”)
]
]
[div[][Html.text“单击此处可移动白色svg正方形的x位置。相对单击坐标如下所示(忽略y坐标)。”]
,div[][Html.text(toString模型)]
]
]
onClickLocation:Html.Attribute Msg
点击位置=
点击
(Json.map)
换位
(反对意见2)
位置
(在[“pageX”]int处)
(在[“pageY”]int处)
)
)
javascript:

const-app=Elm.Main.fullscreen();
app.ports.getParentPos.subscribe(()=>{
const e=document.querySelector(“#parent”);
const rect=e.getBoundingClientRect();
app.ports.parentPos.send({
顶部:数学圆(矩形顶部),
左:数学圆(右左)
});
});

以下是使用VirtualDom的示例的固定版本。我也将它升级到elm v0.18。 注意,就像接受的答案一样,这只得到了pageX/pageY位置,而不是相对位置。我没有详细说明

相关更改从底部开始,从单击位置开始

import Html exposing (Html, div)
import Html.Attributes
import Html.Events exposing (on)
import Json.Decode as Json exposing (..)
import Svg exposing (svg, rect)
import Svg.Attributes exposing (..)
import VirtualDom

main =
  Html.beginnerProgram
    { model = model
    , view = view
    , update = update
    }

type alias Position =
    { x : Int
    , y : Int
    }

type alias Model =
  Position

type Msg
  = ChangePosition Position

model : Model
model =
  Position 0 0

update : Msg -> Model -> Model
update msg _ =
  case Debug.log "msg" msg of
    ChangePosition position ->
      position

view : Model -> Html Msg
view model =
  div []
    [ svg
        [ width "400"
        , height "100"
        , viewBox "0 0 400 100"
        ]
        [ rect
            [ onClickLocation -- this should work but does nothing
            , width "400"
            , height "100"
            , x "0"
            , y "0"
            , fill "#000"
            , cursor "pointer"
            ]
            []
        , rect
            [ width "50"
            , height "50"
            , x (toString model.x)
            , y "20"
            , fill "#fff"
            ]
            []
        ]
    , div
        [ onClickLocation -- this works
        , Html.Attributes.style
            [ ( "background-color", "white" )
            , ( "border", "2px solid black" )
            , ( "width", "400px" )
            , ( "height", "100px" )
            , ( "position", "absolute" )
            , ( "left", "0px" )
            , ( "top", "150px" )
            , ( "color", "black" )
            , ( "cursor", "pointer" )
            ]
        ]
        [ div [] [ Html.text "Click in here to move x position of white svg square. Relative click coordinates shown below (y coordinate ignored)." ]
        , div [] [ Html.text (toString model) ]
        ]
    ]

onClickLocation : Html.Attribute Msg
onClickLocation =
    mouseClick ChangePosition


offsetPosition : Json.Decoder Position
offsetPosition =
    Json.map2 Position (field "pageX" Json.int) (field "pageY" Json.int)


mouseEvent : String -> (Position -> msg) -> VirtualDom.Property msg
mouseEvent event messager =
    let
        options =
            { preventDefault = True, stopPropagation = True }
    in
        VirtualDom.onWithOptions event options (Json.map messager offsetPosition)


mouseClick : (Position -> msg) -> VirtualDom.Property msg
mouseClick =
    mouseEvent "click"

我认为应该使用
Svg.Events
而不是
Html.Events
。顺便说一句,我没有发现event.target.offsetLeft存在于事件中
import Html exposing (Html, div)
import Html.Attributes
import Html.Events exposing (on)
import Json.Decode as Json exposing (..)
import Svg exposing (svg, rect)
import Svg.Attributes exposing (..)
import VirtualDom

main =
  Html.beginnerProgram
    { model = model
    , view = view
    , update = update
    }

type alias Position =
    { x : Int
    , y : Int
    }

type alias Model =
  Position

type Msg
  = ChangePosition Position

model : Model
model =
  Position 0 0

update : Msg -> Model -> Model
update msg _ =
  case Debug.log "msg" msg of
    ChangePosition position ->
      position

view : Model -> Html Msg
view model =
  div []
    [ svg
        [ width "400"
        , height "100"
        , viewBox "0 0 400 100"
        ]
        [ rect
            [ onClickLocation -- this should work but does nothing
            , width "400"
            , height "100"
            , x "0"
            , y "0"
            , fill "#000"
            , cursor "pointer"
            ]
            []
        , rect
            [ width "50"
            , height "50"
            , x (toString model.x)
            , y "20"
            , fill "#fff"
            ]
            []
        ]
    , div
        [ onClickLocation -- this works
        , Html.Attributes.style
            [ ( "background-color", "white" )
            , ( "border", "2px solid black" )
            , ( "width", "400px" )
            , ( "height", "100px" )
            , ( "position", "absolute" )
            , ( "left", "0px" )
            , ( "top", "150px" )
            , ( "color", "black" )
            , ( "cursor", "pointer" )
            ]
        ]
        [ div [] [ Html.text "Click in here to move x position of white svg square. Relative click coordinates shown below (y coordinate ignored)." ]
        , div [] [ Html.text (toString model) ]
        ]
    ]

onClickLocation : Html.Attribute Msg
onClickLocation =
    mouseClick ChangePosition


offsetPosition : Json.Decoder Position
offsetPosition =
    Json.map2 Position (field "pageX" Json.int) (field "pageY" Json.int)


mouseEvent : String -> (Position -> msg) -> VirtualDom.Property msg
mouseEvent event messager =
    let
        options =
            { preventDefault = True, stopPropagation = True }
    in
        VirtualDom.onWithOptions event options (Json.map messager offsetPosition)


mouseClick : (Position -> msg) -> VirtualDom.Property msg
mouseClick =
    mouseEvent "click"