oxyplot 点击x,y交汇的点,标签一直显示

文章描述了一个在前端图形库中实现自定义触摸事件绑定和追踪器行为的示例。通过TouchPlotGrid组件,设置了BindToMouseDown属性以响应左侧鼠标点击,并使用ShowTrackerAndLeaveOpenBehavior类来控制追踪器的行为,包括在鼠标按下时显示并保持追踪器打开。代码中还包括了后台如何设置这一行为以及相关的事件处理和控制器操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       前端:

<local:TouchPlot Grid.Row="1" x:Name="pv" local:ShowTrackerAndLeaveOpenBehavior.BindToMouseDown="Left" Margin="0,0,5,0"  />

如果你是后台写,就这样:

 TouchPlot plt = new TouchPlot { Model = GetPlot() };//GetPlot()是自定义方法
 ShowTrackerAndLeaveOpenBehavior.SetBindToMouseDown(plt, OxyMouseButton.Left);


 自定义的类

public class TouchPlot : PlotView
    {
        protected override void OnTouchDown(TouchEventArgs e)
        {
            var args = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
            args.RoutedEvent = PreviewMouseLeftButtonDownEvent;
            args.Source = e.OriginalSource;
            RaiseEvent(args);
            e.Handled = true;
        }
    }

public static class ShowTrackerAndLeaveOpenBehavior
    {
        public static readonly DependencyProperty BindToMouseDownProperty = DependencyProperty.RegisterAttached(
            "BindToMouseDown", typeof(OxyMouseButton), typeof(ShowTrackerAndLeaveOpenBehavior),
            new PropertyMetadata(default(OxyMouseButton), OnBindToMouseButtonChanged));

        [AttachedPropertyBrowsableForType(typeof(IPlotView))]
        public static void SetBindToMouseDown(DependencyObject element, OxyMouseButton value) =>
            element.SetValue(BindToMouseDownProperty, value);

        [AttachedPropertyBrowsableForType(typeof(IPlotView))]
        public static OxyMouseButton GetBindToMouseDown(DependencyObject element) =>
            (OxyMouseButton)element.GetValue(BindToMouseDownProperty);

        private static void OnBindToMouseButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is IPlotView plot))
                throw new InvalidOperationException($"Can only be applied to {nameof(IPlotView)}");

            //if (plot.ActualModel == null)
            //    throw new InvalidOperationException("Plot has no model");

            var controller = plot.ActualController;
            if (controller == null)
                throw new InvalidOperationException("Plot has no controller");

            if (e.OldValue is OxyMouseButton oldButton && oldButton != OxyMouseButton.None)
                controller.UnbindMouseDown(oldButton);

            var newButton = GetBindToMouseDown(d);
            if (newButton == OxyMouseButton.None)
                return;

            controller.UnbindMouseDown(newButton);
            controller.BindMouseDown(newButton, new DelegatePlotCommand<OxyMouseDownEventArgs>(
                AddStayOpenTrackerManipulator));
        }

        private static void AddStayOpenTrackerManipulator(IPlotView view, IController controller,
            OxyMouseDownEventArgs e)
        {
            controller.AddMouseManipulator(view, new StayOpenTrackerManipulator(view), e);
        }

        private class StayOpenTrackerManipulator : TrackerManipulator
        {
            private readonly PlotModel _plotModel;
            private bool _isTrackerOpen;

            public StayOpenTrackerManipulator(IPlotView plot)
                : base(plot)
            {
                _plotModel = plot?.ActualModel;

                Snap = true;
                PointsOnly = false;
            }

            public override void Started(OxyMouseEventArgs e)
            {
                if (_plotModel != null) { _plotModel.TrackerChanged += HandleTrackerChanged; }
                base.Started(e);
            }

            public override void Completed(OxyMouseEventArgs e)
            {
                if (!_isTrackerOpen)
                {
                    ReallyCompleted(e);
                }
                else
                {
                    // Completed() is called as soon as the mouse button is released.
                    // We won't call the base Completed() here since that would hide the tracker.
                    // Instead, defer the call until one of the hooked events occurs.
                    // The caller will still remove us from the list of active manipulators as soon as we return,
                    // but that's good; otherwise the tracker would continue to move around as the mouse does.
                    new DeferredCompletedCall(_plotModel, () => ReallyCompleted(e)).HookUp();
                }
            }

            private void ReallyCompleted(OxyMouseEventArgs e)
            {
                base.Completed(e);

                // Must unhook or this object will live as long as the model (instead of as long as the manipulation)
                if (_plotModel != null) { _plotModel.TrackerChanged -= HandleTrackerChanged; }
            }

            private void HandleTrackerChanged(object sender, TrackerEventArgs e) =>
                _isTrackerOpen = e.HitResult != null;

            /// <summary>
            /// Monitors events that should trigger manipulator completion and calls an injected function when they fire
            /// </summary>
            private class DeferredCompletedCall
            {
                private readonly PlotModel _plotModel;
                private readonly Action _completed;

                public DeferredCompletedCall(PlotModel plotModel, Action completed)
                {
                    _plotModel = plotModel;
                    _completed = completed;
                }

                /// <summary>
                /// Start monitoring events. Their observer lists will keep us alive until <see cref="Unhook"/> is called.
                /// </summary>
                public void HookUp()
                {
                    Unhook();

                    _plotModel.MouseDown += HandleMouseDown;
                    _plotModel.Updated += HandleUpdated;
                    _plotModel.MouseLeave += HandleMouseLeave;
                }

                /// <summary>
                /// Stop watching events. If they were the only things keeping us alive, we'll turn into garbage.
                /// </summary>
                private void Unhook()
                {
                    _plotModel.MouseDown -= HandleMouseDown;
                    _plotModel.Updated -= HandleUpdated;
                    _plotModel.MouseLeave -= HandleMouseLeave;
                }

                private void CallCompletedAndUnhookEvents()
                {
                    _completed();
                    Unhook();
                }

                private void HandleUpdated(object sender, EventArgs e) => CallCompletedAndUnhookEvents();

                private void HandleMouseLeave(object sender, OxyMouseEventArgs e) => CallCompletedAndUnhookEvents();

                private void HandleMouseDown(object sender, OxyMouseDownEventArgs e)
                {
                    CallCompletedAndUnhookEvents();

                    // Since we're not setting e.Handled to true here, this click will have its regular effect in
                    // addition to closing the tracker; e.g. it could open the tracker again at the new position.
                    // Modify this code if that's not what you want.
                }
            }
        }
    }

<think>好的,用户问的是ECharts中如何让x轴和y轴在0相交。我需要先回忆一下ECharts的相关配置,确保自己理解正确。 首先,ECharts的坐标轴默认情况下可能不会在0相交,尤其是当数据范围不是从零开始的时候。比如,如果数据都是正数,y轴可能不会延伸到负数区域,导致x轴和y轴在y轴的最低相交,而不是0。这时候需要调整坐标轴的配置,让它们强制在0交汇。 我记得ECharts的xAxis和yAxis配置项里有一个属性叫boundaryGap,可能和这个有关。不过boundaryGap主要是控制坐标轴两边是否留白,可能不是直接控制交汇的。可能需要设置坐标轴的范围,比如设置yAxis的min为0,或者根据数据情况调整xAxis的min。 不过用户的需求是让x轴和y轴在0相交,不管数据范围如何。这时候可能需要确保两个轴的0显示在图表上。例如,如果y轴的数据有正有负,x轴可能需要延伸到y轴的0位置,反之亦然。 另外,ECharts有一个xAxis.axisLine.onZero属性,设为true的话可以让x轴在y轴的0位置显示。同样,yAxis.axisLine.onZero可以让y轴在x轴的0位置显示。这可能是关键配置项。需要确认一下这个属性的正确用法。 比如,如果想让x轴在y轴的0位置相交,应该设置xAxis.axisLine.onZero为true。同时,确保y轴的0在图表范围内,可能需要设置yAxis.min和max,或者让ECharts自动计算合适的范围,但包含0。如果数据中没有负数,可能需要手动设置yAxis.min为0,否则x轴可能不会移动到0的位置。 另外,坐标轴类型也可能影响这个行为,比如是数值轴(value)还是类目轴(category)。数值轴的话,设置onZero应该有效,而类目轴可能不支持。需要确认用户的数据轴类型是否正确。 总结下来,步骤可能是这样的:首先确保x轴和y轴都是数值轴,然后分别设置它们的axisLine.onZero为true,并且调整轴的min和max值,确保0在轴上可见。这样两个轴就会在0交汇了。 还需要检查是否有其他配置可能影响这个行为,比如grid的设置,或者坐标轴的位置(如xAxis.position设置为'bottom'或'top',yAxis.position设置为'left'或'right'),但通常onZero属性应该能处理大部分情况。 举个例子,如果用户的数据y轴范围是-5到5,那么默认情况下x轴可能在中间,也就是0位置。但如果数据全是正数,比如1到10,那么y轴可能从1开始,x轴就不会在0交汇。这时候需要设置yAxis.min为0,并且启用xAxis.axisLine.onZero为true,这样x轴就会在y轴的0位置显示,而y轴也会从0开始,从而交汇在0。 可能需要提醒用户,如果数据中没有0,可能需要手动设置轴的min或max,确保0被包含进去,否则即使设置了onZero,轴也不会在0交汇,因为0不在轴的范围内。 最后,可能还需要考虑双轴的情况,比如多个y轴或x轴,这时候需要指定哪个轴作为基准,但一般情况下,主轴的配置应该足够。 总结回答的结构应该是先解释onZero属性的作用,然后说明如何配置xAxis和yAxis的axisLine.onZero,以及可能需要调整min/max来确保0在轴上。最后给出一个配置示例,帮助用户理解具体的代码写法。</think>在 ECharts 中实现 **x 轴与 y 轴在 0 相交**,需要通过配置坐标轴属性控制交汇行为。以下是逐步说明: --- ### 一、默认行为分析 - 当数据均为正数时,y 轴默认从最小值开始,x 轴可能不与 y 轴的 0 对齐。 - 当数据包含正负数时,ECharts 可能自动扩展轴范围,使 x 轴和 y 轴在 0 相交。 --- ### 二、关键配置属性 通过以下属性强制坐标轴在 0 交汇: 1. **`xAxis.axisLine.onZero`** - 作用:控制 x 轴是否在 y 轴的 **0 值位置** 显示。 - 默认值:`true`(当数据包含正负数时自动生效)。 - 需显式设置为 `true` 以确保强制对齐。 2. **`yAxis.axisLine.onZero`** - 作用:控制 y 轴是否在 x 轴的 **0 值位置** 显示。 - 适用场景较少,通常只需配置 `xAxis.axisLine.onZero`。 3. **手动设置轴范围** - 若数据未包含 0 ,需通过 `min`/`max` 强制包含 0: ```javascript yAxis: { min: 0, // 强制 y 轴从 0 开始 max: 100 } ``` --- ### 三、完整配置示例 ```javascript option = { xAxis: { type: 'value', axisLine: { onZero: true // 强制 x 轴对齐到 y 轴的 0 } }, yAxis: { type: 'value', min: 0, // 确保 y 轴包含 0 axisLine: { onZero: true // 可选,控制 y 轴对齐到 x 轴的 0 } }, series: [{ type: 'line', data: [[5, 10], [10, 20], [15, 30]] }] }; ``` --- ### 四、特殊场景处理 1. **数据全为正值时**: - 需显式设置 `yAxis.min: 0`,否则 y 轴可能从数据最小值开始。 2. **类目轴(category)**: - `onZero` 属性对类目轴无效,需改用数值轴(`type: 'value'`)。 --- ### 五、效果验证 - 打开 ECharts 官方示例编辑器,粘贴上述配置。 - 调整 `min`/`max` 或 `onZero` 属性,观察坐标轴交汇变化。 通过以上配置,可确保 x 轴和 y 轴始终在 0 相交,适应大多数数据可视化需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值