gpt4 book ai didi

svg - Elm:向 SVG 元素添加点击事件不起作用——这可能吗?

转载 作者:行者123 更新时间:2023-12-04 05:15:50 25 4
gpt4 key购买 nike

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

下面给出了一个代码示例,您可以尝试在 http://elm-lang.org/try 上运行,以显示 HTML 元素上的点击事件如何按预期工作,但在 SVG 元素上却没有。

在示例中,使用 Html.on "click" 而不是 Html.onClick 来允许从事件中解码位置数据,如 this discussion 中所述。

阅读文档和源代码后,我希望将 on "click" 事件添加到 SVG 元素时,它的工作方式与将事件添加到 HTML 元素的方式相同。但是,当这样做时,单击 SVG 元素不会触发该事件,也不会向更新函数发送消息。

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

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

在 stackoverflow here 上也有人问过一个类似的问题,但这是指 Canvas 形状,据我所知,这是一个完全独立的问题(虽然我可能错了)。

代码示例:

import Html exposing (Html, div)
import Html.App as App
import Html.Attributes
import Html.Events exposing (on)
import Json.Decode as Json exposing (object2, int, at)
import Mouse exposing (Position)
import Svg exposing (svg, rect)
import Svg.Attributes exposing (..)

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

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 =
on "click"
(Json.map
ChangePosition
(object2
Position
(object2 (-)
(at [ "pageX" ] int)
(at [ "target", "offsetLeft" ] int)
)
(object2 (-)
(at [ "pageY" ] int)
(at [ "target", "offsetTop" ] int)
)
)
)

最佳答案

Json 解码器不起作用的原因很明显,因为offsetLeftoffsetTop 都不存在
事件对象。

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

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

port module Main exposing (main)

import Html exposing (Html, div)
import Html.App as App
import Html.Attributes
import Html.Events exposing (on)
import Json.Decode as Json exposing (object2, object1, int, at)
import Mouse exposing (Position)
import Svg exposing (svg, rect)
import Svg.Attributes exposing (..)

main : Program Never
main =
App.program
{ init = (initmodel, getParentPos ())
, view = view
, update = update
, subscriptions = subscriptions
}

type alias Model =
{ position : Position
, parentPosition : Position
}

type Msg
= ChangePosition Position
| UpdateParentPosition { top : Int, left : Int }

initmodel : Model
initmodel =
{ position = Position 0 0
, parentPosition = Position 0 0
}

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case Debug.log "msg" msg of
ChangePosition position ->
let
relativepos = Position
( 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)

port getParentPos : () -> Cmd msg

subscriptions : Model -> Sub Msg
subscriptions model =
parentPos UpdateParentPosition

port parentPos : ({ top : Int, left : Int } -> msg) -> Sub msg

view : Model -> Html Msg
view model =
div []
[ svg
[ width "400"
, height "100"
, viewBox "0 0 400 100"
, id "parent"
]
[ 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.position.x)
, y (toString model.position.y)
, 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 =
on "click"
(Json.map
ChangePosition
(object2
Position
(at [ "pageX" ] int)
(at [ "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({
top: Math.round(rect.top),
left: Math.round(rect.left)
});
});

关于svg - Elm:向 SVG 元素添加点击事件不起作用——这可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40269494/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com