UNPKG

14.1 kBJavaScriptView Raw
1var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5 return c > 3 && r && Object.defineProperty(target, key, r), r;
6};
7var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8 if (kind === "m") throw new TypeError("Private method is not writable");
9 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11 return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12};
13var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
14 if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
15 if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
16 return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
17};
18var _DuoyunMapElement_projection, _DuoyunMapElement_areas, _DuoyunMapElement_onPan, _DuoyunMapElement_onEnd, _DuoyunMapElement_onLeaveArea, _DuoyunMapElement_onLeaveNode, _DuoyunMapElement_renderArea, _DuoyunMapElement_renderName, _DuoyunMapElement_renderNode;
19var DuoyunMapElement_1;
20import { adoptedStyle, customElement, emitter, property, state, part } from '@mantou/gem/lib/decorators';
21import { html, svg } from '@mantou/gem/lib/element';
22import { createCSSSheet, css, styleMap, classMap } from '@mantou/gem/lib/utils';
23import { geoProjection, geoMercatorRaw, geoEquirectangularRaw, geoPath } from 'd3-geo';
24import { theme } from '../lib/theme';
25import { DuoyunLoadableBaseElement } from './base/loadable';
26import './gesture';
27// https://github.com/d3/d3-geo/blob/main/src/projection/equirectangular.js
28// https://github.com/d3/d3-geo/blob/main/src/projection/mercator.js
29const customProjectionRaw = (lambda, phi) => {
30 const limit = (Math.PI / 180) * 53;
31 const maxPhi = (Math.PI / 180) * 95;
32 const total = maxPhi - limit;
33 const [, y1] = geoEquirectangularRaw(lambda, phi);
34 const [, y2] = geoMercatorRaw(lambda, phi);
35 const phiAbs = Math.abs(phi);
36 const ratio = phiAbs > limit ? (phiAbs - limit) / total : 0;
37 const y = y1 * ratio + y2 * (1 - ratio);
38 return [lambda, y];
39};
40// TODO: implement `invert`
41export const geoCommonProjection = () => geoProjection(customProjectionRaw).scale(152.63);
42// viewbox 1
43// https://www.zhangxinxu.com/sp/svgo/
44export const shapes = [
45 // 圆
46 {
47 strokeScale: 1,
48 scale: 2,
49 d: 'M1 .36A.5.5 0 0 1 .64 1 .5.5 0 0 1 0 .64a.42.42 0 0 1 0-.27A.49.49 0 0 1 .63 0 .51.51 0 0 1 1 .29z',
50 },
51 // 三边形
52 {
53 strokeScale: 0.9,
54 scale: 2,
55 d: 'M.5109 0.01L.0087 .88h1.0046L.5109 .01z',
56 },
57 // 菱形
58 {
59 strokeScale: 0.8,
60 scale: 2,
61 d: 'M0.00704 0.5071l0.5-0.5 0.5 0.5-0.5 0.5z',
62 },
63 // 五边形
64 {
65 strokeScale: 0.8,
66 scale: 2,
67 d: 'M0.5030.0062L0.0059 0.3674l0.1899 0.5844h0.6145l0.19-0.5844L0.5030.0062z',
68 },
69 // 六角
70 {
71 strokeScale: 0.7,
72 scale: 2.5,
73 d: 'M.73.48L.86.25H.6L.43 0 .3.23H0l.13.25L0 .75h.26L.43 1 .56.77h.3L.73.52V.48z',
74 },
75 // 四角
76 {
77 strokeScale: 0.7,
78 scale: 3,
79 d: 'M0.4974 0L0.3709 0.3726 0 0.4988l0.3692 0.1286L0.4974 1l0.1255-0.372L0.9972 0.5 0.6263 0.3744z',
80 },
81 // 五角
82 {
83 strokeScale: 0.7,
84 scale: 2.5,
85 d: 'M0.5107 0.8l-0.309 0.1624 0.059-0.344-0.25-0.2437 0.3455-0.0502L0.5107 0.0113l0.1546 0.3131 0.3454 0.0502-0.25 0.2437 0.0591 0.344-0.3091-0.1624z',
86 },
87 // 正方形
88 {
89 strokeScale: 0.9,
90 scale: 2,
91 d: 'M0 0L0 1L1 1L1 0z',
92 },
93];
94const style = createCSSSheet(css `
95 :host(:where(:not([hidden]))) {
96 display: block;
97 border-radius: ${theme.normalRound};
98 background-color: ${theme.lightBackgroundColor};
99 aspect-ratio: 2 / 1;
100 }
101 svg {
102 overflow: visible;
103 }
104 .area {
105 stroke: ${theme.backgroundColor};
106 transition: opacity 0.3s ${theme.timingFunction};
107 }
108 .area.current:not(.disabled):hover {
109 opacity: 0.8;
110 }
111 .name {
112 fill: ${theme.textColor};
113 stroke: ${theme.backgroundColor};
114 paint-order: stroke;
115 pointer-events: none;
116 text-anchor: middle;
117 }
118 .node {
119 paint-order: stroke;
120 transform-origin: center;
121 transform-box: fill-box;
122 stroke-opacity: 0.4;
123 --translate: calc(-50% + var(--x)), calc(-50% + var(--y));
124 transform: translate(var(--translate)) scale(var(--scale));
125 /* await chrome implement */
126 transition: scale 0.3s ${theme.timingFunction};
127 }
128 .node.current:hover {
129 transform: translate(var(--translate)) scale(calc(var(--scale) * 1.5));
130 }
131`);
132/**
133 * @customElement dy-map
134 * @fire nodehover
135 * @fire nodeleave
136 * @fire nodeclick
137 * @fire areahover
138 * @fire arealeave
139 * @fire areaclick
140 */
141let DuoyunMapElement = DuoyunMapElement_1 = class DuoyunMapElement extends DuoyunLoadableBaseElement {
142 constructor() {
143 super();
144 this.scale = 1;
145 this.translate2D = [0, 0];
146 this.state = {};
147 _DuoyunMapElement_projection.set(this, void 0);
148 _DuoyunMapElement_areas.set(this, void 0);
149 _DuoyunMapElement_onPan.set(this, ({ detail }) => {
150 this.grabbing = true;
151 this.pan(detail);
152 });
153 _DuoyunMapElement_onEnd.set(this, () => {
154 this.grabbing = false;
155 });
156 _DuoyunMapElement_onLeaveArea.set(this, (detail) => {
157 this.arealeave(detail);
158 this.setState({ currentArea: undefined });
159 });
160 _DuoyunMapElement_onLeaveNode.set(this, (detail) => {
161 this.nodeleave(detail);
162 this.setState({ currentNode: undefined });
163 });
164 this.willMount = () => {
165 this.memo(() => {
166 var _a, _b;
167 __classPrivateFieldSet(this, _DuoyunMapElement_projection, ((_a = this.getProjection) === null || _a === void 0 ? void 0 : _a.call(this, geoCommonProjection)) || geoCommonProjection(), "f");
168 const pathFn = geoPath().projection(__classPrivateFieldGet(this, _DuoyunMapElement_projection, "f"));
169 __classPrivateFieldSet(this, _DuoyunMapElement_areas, (_b = this.geo) === null || _b === void 0 ? void 0 : _b.features.map(({ geometry, properties }) => {
170 return {
171 path: pathFn(geometry),
172 center: pathFn.centroid(geometry),
173 name: (properties && (properties.name || properties.NAME)) || '',
174 };
175 }), "f");
176 }, () => [this.geo, this.getProjection]);
177 };
178 _DuoyunMapElement_renderArea.set(this, (area, isCurrent) => {
179 var _a;
180 const { name, path } = area;
181 const color = (_a = this.getAreaColor) === null || _a === void 0 ? void 0 : _a.call(this, name, isCurrent);
182 const onMouseover = (originEvent) => {
183 if (isCurrent) {
184 this.areahover({ name, originEvent });
185 }
186 else {
187 this.setState({ currentArea: area });
188 }
189 };
190 return svg `
191 <path
192 class=${classMap({ area: true, disabled: !color, current: isCurrent })}
193 d=${path}
194 stroke-width=${0.1 / this.scale}
195 fill=${color || theme.disabledColor}
196 @click=${(originEvent) => this.areaclick({ name, originEvent })}
197 @mouseover=${onMouseover}
198 @mouseout=${(originEvent) => isCurrent && __classPrivateFieldGet(this, _DuoyunMapElement_onLeaveArea, "f").call(this, { name, originEvent })}
199 ></path>
200 `;
201 });
202 _DuoyunMapElement_renderName.set(this, ({ name, center: [x, y] }, isCurrent) => {
203 var _a;
204 return svg `
205 <text
206 class=${classMap({ name: true, current: isCurrent })}
207 x=${x}
208 y=${y}
209 font-size=${2.5 / this.scale}
210 stroke-width=${0.5 / this.scale}>
211 ${(_a = this.getAreaName) === null || _a === void 0 ? void 0 : _a.call(this, name, isCurrent)}
212 </text>
213 `;
214 });
215 _DuoyunMapElement_renderNode.set(this, (node, isCurrent) => {
216 var _a;
217 const { id, type = '0', position: pos } = node;
218 const position = __classPrivateFieldGet(this, _DuoyunMapElement_projection, "f").call(this, pos) || [0, 0];
219 const color = ((_a = this.getNodeColor) === null || _a === void 0 ? void 0 : _a.call(this, id, isCurrent)) || theme.textColor;
220 const shape = shapes[type];
221 const scale = shape.scale / this.scale;
222 const onMouseover = (originEvent) => {
223 if (isCurrent) {
224 this.nodehover({ id, originEvent });
225 }
226 else {
227 this.setState({ currentNode: node });
228 }
229 };
230 return svg `
231 <path
232 class=${classMap({ node: true, current: isCurrent })}
233 style=${`--x: ${position[0]}px; --y: ${position[1]}px; --scale: ${scale}`}
234 d=${shape.d}
235 fill=${color}
236 stroke=${theme.backgroundColor}
237 stroke-width=${(2 / scale) * shape.strokeScale}
238 @click=${(originEvent) => this.nodeclick({ id, originEvent })}
239 @mouseover=${onMouseover}
240 @mouseout=${(originEvent) => isCurrent && __classPrivateFieldGet(this, _DuoyunMapElement_onLeaveNode, "f").call(this, { id, originEvent })}
241 ></path>
242 `;
243 });
244 this.render = () => {
245 var _a, _b, _c;
246 const { currentArea, currentNode } = this.state;
247 return html `
248 <dy-gesture @pan=${__classPrivateFieldGet(this, _DuoyunMapElement_onPan, "f")} @end=${__classPrivateFieldGet(this, _DuoyunMapElement_onEnd, "f")}>
249 ${svg `
250 <svg
251 part=${DuoyunMapElement_1.map}
252 xmlns="http://www.w3.org/2000/svg"
253 viewBox="-180 -90 360 180"
254 aria-hidden="true"
255 style=${styleMap({
256 transform: `scale(${this.scale}) translate(${this.translate2D[0]}px, ${this.translate2D[1]}px)`,
257 })}>
258 ${(_a = __classPrivateFieldGet(this, _DuoyunMapElement_areas, "f")) === null || _a === void 0 ? void 0 : _a.map((area) => (area === currentArea ? '' : __classPrivateFieldGet(this, _DuoyunMapElement_renderArea, "f").call(this, area, false)))}
259 ${currentArea ? __classPrivateFieldGet(this, _DuoyunMapElement_renderArea, "f").call(this, currentArea, true) : ''}
260 ${(_b = __classPrivateFieldGet(this, _DuoyunMapElement_areas, "f")) === null || _b === void 0 ? void 0 : _b.map((area) => __classPrivateFieldGet(this, _DuoyunMapElement_renderName, "f").call(this, area, false))}
261 ${currentArea ? __classPrivateFieldGet(this, _DuoyunMapElement_renderName, "f").call(this, currentArea, true) : ''}
262 ${__classPrivateFieldGet(this, _DuoyunMapElement_areas, "f") && ((_c = this.nodes) === null || _c === void 0 ? void 0 : _c.map((node) => (node === currentNode ? '' : __classPrivateFieldGet(this, _DuoyunMapElement_renderNode, "f").call(this, node, false))))}
263 ${currentNode ? __classPrivateFieldGet(this, _DuoyunMapElement_renderNode, "f").call(this, currentNode, true) : ''}
264 </svg>
265 `}
266 </dy-gesture>
267 `;
268 };
269 this.internals.role = 'img';
270 }
271};
272_DuoyunMapElement_projection = new WeakMap(), _DuoyunMapElement_areas = new WeakMap(), _DuoyunMapElement_onPan = new WeakMap(), _DuoyunMapElement_onEnd = new WeakMap(), _DuoyunMapElement_onLeaveArea = new WeakMap(), _DuoyunMapElement_onLeaveNode = new WeakMap(), _DuoyunMapElement_renderArea = new WeakMap(), _DuoyunMapElement_renderName = new WeakMap(), _DuoyunMapElement_renderNode = new WeakMap();
273__decorate([
274 property
275], DuoyunMapElement.prototype, "getProjection", void 0);
276__decorate([
277 property
278], DuoyunMapElement.prototype, "geo", void 0);
279__decorate([
280 property
281], DuoyunMapElement.prototype, "getAreaColor", void 0);
282__decorate([
283 property
284], DuoyunMapElement.prototype, "getAreaName", void 0);
285__decorate([
286 property
287], DuoyunMapElement.prototype, "nodes", void 0);
288__decorate([
289 property
290], DuoyunMapElement.prototype, "getNodeColor", void 0);
291__decorate([
292 property
293], DuoyunMapElement.prototype, "scale", void 0);
294__decorate([
295 property
296], DuoyunMapElement.prototype, "translate2D", void 0);
297__decorate([
298 state
299], DuoyunMapElement.prototype, "grabbing", void 0);
300__decorate([
301 emitter
302], DuoyunMapElement.prototype, "pan", void 0);
303__decorate([
304 emitter
305], DuoyunMapElement.prototype, "nodehover", void 0);
306__decorate([
307 emitter
308], DuoyunMapElement.prototype, "nodeleave", void 0);
309__decorate([
310 emitter
311], DuoyunMapElement.prototype, "nodeclick", void 0);
312__decorate([
313 emitter
314], DuoyunMapElement.prototype, "areahover", void 0);
315__decorate([
316 emitter
317], DuoyunMapElement.prototype, "arealeave", void 0);
318__decorate([
319 emitter
320], DuoyunMapElement.prototype, "areaclick", void 0);
321__decorate([
322 part
323], DuoyunMapElement, "map", void 0);
324DuoyunMapElement = DuoyunMapElement_1 = __decorate([
325 customElement('dy-map'),
326 adoptedStyle(style)
327], DuoyunMapElement);
328export { DuoyunMapElement };
329//# sourceMappingURL=map.js.map
\No newline at end of file