如何在反应传单中制作椭圆?

时间:2018-03-03 20:41:56

标签: react-leaflet

我正在尝试使用words.gsub(" ", "0").chars 在地图上绘制椭圆,该内容支持圆形和矩形。

为实现这一目标,我使用代码在here中生成一个椭圆(非反应)react-leaflet,我已在下面修改并粘贴:

leaflet

要创建一个与import * as L from 'leaflet'; L.SVG.include ({ _updateEllipse: function (layer) { var // c = layer._point, rx = layer._radiusX, ry = layer._radiusY, phi = layer._tiltDeg, endPoint = layer._endPointParams; var d = 'M' + endPoint.x0 + ',' + endPoint.y0 + 'A' + rx + ',' + ry + ',' + phi + ',' + endPoint.largeArc + ',' + endPoint.sweep + ',' + endPoint.x1 + ',' + endPoint.y1 + ' z'; this._setPath(layer, d); } }); L.Canvas.include ({ _updateEllipse: function (layer) { if (layer._empty()) { return; } var p = layer._point, ctx = this._ctx, r = layer._radiusX, s = (layer._radiusY || r) / r; this._drawnLayers[layer._leaflet_id] = layer; ctx.save(); ctx.translate(p.x, p.y); if (layer._tilt !== 0) { ctx.rotate( layer._tilt ); } if (s !== 1) { ctx.scale(1, s); } ctx.beginPath(); ctx.arc(0, 0, r, 0, Math.PI * 2); ctx.restore(); this._fillStroke(ctx, layer); }, }); L.Ellipse = L.Path.extend({ options: { fill: true, startAngle: 0, endAngle: 359.9 }, initialize: function (latlng, radii, tilt, options) { L.setOptions(this, options); this._latlng = L.latLng(latlng); if (tilt) { this._tiltDeg = tilt; } else { this._tiltDeg = 0; } if (radii) { this._mRadiusX = radii[0]; this._mRadiusY = radii[1]; } }, setRadius: function (radii) { this._mRadiusX = radii[0]; this._mRadiusY = radii[1]; return this.redraw(); }, getRadius: function () { return new L.point(this._mRadiusX, this._mRadiusY); }, setTilt: function (tilt) { this._tiltDeg = tilt; return this.redraw(); }, getBounds: function () { // TODO respect tilt (bounds are too big) var lngRadius = this._getLngRadius(), latRadius = this._getLatRadius(), latlng = this._latlng; return new L.LatLngBounds( [latlng.lat - latRadius, latlng.lng - lngRadius], [latlng.lat + latRadius, latlng.lng + lngRadius]); }, // @method setLatLng(latLng: LatLng): this // Sets the position of a circle marker to a new location. setLatLng: function (latlng) { this._latlng = L.latLng(latlng); this.redraw(); return this.fire('move', {latlng: this._latlng}); }, // @method getLatLng(): LatLng // Returns the current geographical position of the circle marker getLatLng: function () { return this._latlng; }, setStyle: L.Path.prototype.setStyle, _project: function () { var lngRadius = this._getLngRadius(), latRadius = this._getLatRadius(), latlng = this._latlng, pointLeft = this._map.latLngToLayerPoint([latlng.lat, latlng.lng - lngRadius]), pointBelow = this._map.latLngToLayerPoint([latlng.lat - latRadius, latlng.lng]); this._point = this._map.latLngToLayerPoint(latlng); this._radiusX = Math.max(this._point.x - pointLeft.x, 1); this._radiusY = Math.max(pointBelow.y - this._point.y, 1); this._tilt = Math.PI * this._tiltDeg / 180; this._endPointParams = this._centerPointToEndPoint(); this._updateBounds(); }, _updateBounds: function () { // http://math.stackexchange.com/questions/91132/how-to-get-the-limits-of-rotated-ellipse var sin = Math.sin(this._tilt); var cos = Math.cos(this._tilt); var sinSquare = sin * sin; var cosSquare = cos * cos; var aSquare = this._radiusX * this._radiusX; var bSquare = this._radiusY * this._radiusY; var halfWidth = Math.sqrt(aSquare*cosSquare+bSquare*sinSquare); var halfHeight = Math.sqrt(aSquare*sinSquare+bSquare*cosSquare); var w = this._clickTolerance(); var p = [halfWidth + w, halfHeight + w]; this._pxBounds = new L.Bounds(this._point.subtract(p), this._point.add(p)); }, _update: function () { if (this._map) { this._updatePath(); } }, _updatePath: function () { this._renderer._updateEllipse(this); }, _getLatRadius: function () { return (this._mRadiusY / 40075017) * 360; }, _getLngRadius: function () { return ((this._mRadiusX / 40075017) * 360) / Math.cos((Math.PI / 180) * this._latlng.lat); }, _centerPointToEndPoint: function () { // Convert between center point parameterization of an ellipse // too SVG's end-point and sweep parameters. This is an // adaptation of the perl code found here: // http://commons.oreilly.com/wiki/index.php/SVG_Essentials/Paths var c = this._point, rx = this._radiusX, ry = this._radiusY, theta2 = (this.options.startAngle + this.options.endAngle) * (Math.PI / 180), theta1 = this.options.startAngle * (Math.PI / 180), delta = this.options.endAngle, phi = this._tiltDeg * (Math.PI / 180); // Determine start and end-point coordinates var x0 = c.x + Math.cos(phi) * rx * Math.cos(theta1) + Math.sin(-phi) * ry * Math.sin(theta1); var y0 = c.y + Math.sin(phi) * rx * Math.cos(theta1) + Math.cos(phi) * ry * Math.sin(theta1); var x1 = c.x + Math.cos(phi) * rx * Math.cos(theta2) + Math.sin(-phi) * ry * Math.sin(theta2); var y1 = c.y + Math.sin(phi) * rx * Math.cos(theta2) + Math.cos(phi) * ry * Math.sin(theta2); var largeArc = (delta > 180) ? 1 : 0; var sweep = (delta > 0) ? 1 : 0; return {'x0': x0, 'y0': y0, 'tilt': phi, 'largeArc': largeArc, 'sweep': sweep, 'x1': x1, 'y1': y1}; }, _empty: function () { return this._radiusX && this._radiusY && !this._renderer._bounds.intersects(this._pxBounds); }, _containsPoint : function (p) { // http://stackoverflow.com/questions/7946187/point-and-ellipse-rotated-position-test-algorithm var sin = Math.sin(this._tilt); var cos = Math.cos(this._tilt); var dx = p.x - this._point.x; var dy = p.y - this._point.y; var sumA = cos * dx + sin * dy; var sumB = sin * dx - cos * dy; return sumA * sumA / (this._radiusX * this._radiusX) + sumB * sumB / (this._radiusY * this._radiusY) <= 1; } }); export const lellipse = function (latlng, radii, tilt, options) { return new L.Ellipse(latlng, radii, tilt, options); }; 一起使用的椭圆,我按照Circle in react-leaflet的示例生成了以下react-leaflet组件:

Ellipse

代码的问题在于它不呈现椭圆并且不会抛出任何错误。有人可以建议如何使用import PropTypes from 'prop-types' import { lellipse as LeafletEllipse } from '../l.ellipse'; import Path from './Path' import children from './propTypes/children' import latlng from './propTypes/latlng' import type { LatLng, MapLayerProps, PathOptions } from './types' type LeafletElement = LeafletEllipse type Props = { center: LatLng, mSemiMajorAxis: number, mSemiMinorAxis: number, degreeTiltFromWest: number, } & MapLayerProps & PathOptions & Object export default class Ellipse extends Path<LeafletElement, Props> { static propTypes = { center: latlng.isRequired, mSemiMajorAxis: PropTypes.number.isRequired, mSemiMinorAxis: PropTypes.number.isRequired, degreeTiltFromWest: PropTypes.number.isRequired, children: children, } createLeafletElement(props: Props): LeafletElement { const { center, mSemiMajorAxis, mSemiMinorAxis, degreeTiltFromWest, ...options } = props return new LeafletEllipse(center, [mSemiMajorAxis, mSemiMinorAxis], this.getOptions(options)) } updateLeafletElement(fromProps: Props, toProps: Props) { if (toProps.center !== fromProps.center) { this.leafletElement.setLatLng(toProps.center); } if (toProps.degreeTiltFromWest !== fromProps.degreeTiltFromWest) { this.leafletElement.setTilt(toProps.degreeTiltFromWest); } if (toProps.mSemiMinorAxis !== fromProps.mSemiMinorAxis || toProps.mSemiMajorAxis !== fromProps.mSemiMajorAxis) { this.leafletElement.setRadius([toProps.mSemiMajorAxis, toProps.mSemiMinorAxis]); } } } 渲染椭圆吗?谢谢。

1 个答案:

答案 0 :(得分:1)

您的 createLeafletElement 函数缺少tilt参数。它应该是:

   createLeafletElement(props) {
        const { center, mSemiMajorAxis, mSemiMinorAxis, degreeTiltFromWest, ...options } = props
        return new LeafletEllipse(center, [mSemiMajorAxis, mSemiMinorAxis], degreeTiltFromWest, this.getOptions(options))
    }

请参阅下面的完整文件(在ES6而不是打字稿中,因为我发现它更清晰)。

import React, { PropTypes } from 'react';
import { lellipse as LeafletEllipse } from './l.ellipse';
import { Path, withLeaflet } from 'react-leaflet';

class Ellipse extends Path {

    static propTypes = {
        center: PropTypes.arrayOf(PropTypes.number).isRequired,
        mSemiMajorAxis: PropTypes.number.isRequired,
        mSemiMinorAxis: PropTypes.number.isRequired,
        degreeTiltFromWest: PropTypes.number.isRequired
    }

    createLeafletElement(props) {
        const { center, mSemiMajorAxis, mSemiMinorAxis, degreeTiltFromWest, ...options } = props
        return new LeafletEllipse(center, [mSemiMajorAxis, mSemiMinorAxis], degreeTiltFromWest, this.getOptions(options))
    }

    updateLeafletElement(fromProps, toProps) {
        if (toProps.center !== fromProps.center) {
            this.leafletElement.setLatLng(toProps.center);
        }
        if (toProps.degreeTiltFromWest !== fromProps.degreeTiltFromWest) {
            this.leafletElement.setTilt(toProps.degreeTiltFromWest);
        }
        if (toProps.mSemiMinorAxis !== fromProps.mSemiMinorAxis || toProps.mSemiMajorAxis !== fromProps.mSemiMajorAxis) {
            this.leafletElement.setRadius([toProps.mSemiMajorAxis, toProps.mSemiMinorAxis]);
        }
    }
} 
export default class withLeaflet(Ellipse);