package com.grigowashere.aismap.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import com.grigowashere.aismap.R; import java.util.Locale; /** * Простой аналоговый спидометр (узлы) в стиле картплоттера. */ public class PlotterSpeedometerView extends View { private static final float MAX_SPEED_KNOTS = 30f; private final Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint arcPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint tickPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint needlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint labelPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint valuePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final RectF arcRect = new RectF(); private float speedKnots = 0f; private String title; public PlotterSpeedometerView(Context context) { super(context); init(); } public PlotterSpeedometerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private void init() { title = getContext().getString(R.string.radar_plotter_sog_label); int labelColor = ContextCompat.getColor(getContext(), R.color.plotter_text_label); int textColor = ContextCompat.getColor(getContext(), R.color.plotter_text_primary); int accent = ContextCompat.getColor(getContext(), R.color.plotter_text_accent); bgPaint.setStyle(Paint.Style.STROKE); bgPaint.setStrokeWidth(dp(2)); bgPaint.setColor(0x44FFFFFF); arcPaint.setStyle(Paint.Style.STROKE); arcPaint.setStrokeWidth(dp(6)); arcPaint.setColor(accent); arcPaint.setStrokeCap(Paint.Cap.ROUND); tickPaint.setStyle(Paint.Style.STROKE); tickPaint.setStrokeWidth(dp(1)); tickPaint.setColor(labelColor); needlePaint.setStyle(Paint.Style.STROKE); needlePaint.setStrokeWidth(dp(2.5f)); needlePaint.setColor(accent); needlePaint.setStrokeCap(Paint.Cap.ROUND); labelPaint.setColor(labelColor); labelPaint.setTextSize(dp(10)); labelPaint.setLetterSpacing(0.08f); valuePaint.setColor(textColor); valuePaint.setTextSize(dp(18)); valuePaint.setFakeBoldText(true); } public void setSpeedKnots(double knots) { float v = (float) Math.max(0.0, Math.min(MAX_SPEED_KNOTS, knots)); if (Math.abs(v - speedKnots) > 0.05f) { speedKnots = v; invalidate(); } } @Override protected void onDraw(Canvas canvas) { int w = getWidth(); int h = getHeight(); if (w <= 0 || h <= 0) return; float pad = dp(8); float titleY = dp(14); canvas.drawText(title, w * 0.5f - labelPaint.measureText(title) / 2f, titleY, labelPaint); float cx = w * 0.5f; float bottom = h - pad; float maxRadius = Math.min((w - 2f * pad) * 0.5f, bottom - titleY - pad); float radius = Math.max(dp(12), maxRadius * 0.88f); float cy = bottom; arcRect.set(cx - radius, cy - radius, cx + radius, cy + radius); canvas.drawArc(arcRect, 180f, 180f, false, bgPaint); float sweep = 180f * (speedKnots / MAX_SPEED_KNOTS); canvas.drawArc(arcRect, 180f, sweep, false, arcPaint); for (int k = 0; k <= 30; k += 5) { float frac = k / MAX_SPEED_KNOTS; double ang = Math.toRadians(180 + 180 * frac); float x1 = cx + (float) (Math.cos(ang) * (radius - dp(4))); float y1 = cy + (float) (Math.sin(ang) * (radius - dp(4))); float x2 = cx + (float) (Math.cos(ang) * radius); float y2 = cy + (float) (Math.sin(ang) * radius); canvas.drawLine(x1, y1, x2, y2, tickPaint); if (k % 10 == 0) { String t = String.valueOf(k); float tw = labelPaint.measureText(t); canvas.drawText(t, cx + (float) (Math.cos(ang) * (radius - dp(16))) - tw / 2f, cy + (float) (Math.sin(ang) * (radius - dp(16))) + dp(4), labelPaint); } } double needleAng = Math.toRadians(180 + 180 * (speedKnots / MAX_SPEED_KNOTS)); float nx = cx + (float) (Math.cos(needleAng) * (radius - dp(10))); float ny = cy + (float) (Math.sin(needleAng) * (radius - dp(10))); canvas.drawLine(cx, cy, nx, ny, needlePaint); canvas.drawCircle(cx, cy, dp(4), needlePaint); String val = String.format(Locale.US, "%.1f", speedKnots); canvas.drawText(val, cx - valuePaint.measureText(val) / 2f, cy - dp(6), valuePaint); String unit = "kn"; canvas.drawText(unit, cx - labelPaint.measureText(unit) / 2f, cy + dp(12), labelPaint); } private float dp(float v) { return v * getResources().getDisplayMetrics().density; } }