@ray-js/lamp-circle-picker 1.0.12-beta-3 → 1.0.13-beta-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -129,7 +129,7 @@ export default Render({
129
129
  return null;
130
130
  },
131
131
 
132
- drawRingWithConicGradient(params) {
132
+ drawRingWithGradientSegments(params) {
133
133
  let {
134
134
  startAngle,
135
135
  endAngle,
@@ -142,6 +142,7 @@ export default Render({
142
142
  centerX,
143
143
  centerY,
144
144
  ringBorderColor,
145
+ lineCap = 'round',
145
146
  } = params;
146
147
 
147
148
  // 检查 canvas 和 context
@@ -258,13 +259,105 @@ export default Render({
258
259
  ctx.fill();
259
260
  ctx.closePath();
260
261
  }
261
- ctx.globalCompositeOperation = 'destination-out';
262
+
263
+ // 返回渐变颜色数组,供后续绘制端点使用
264
+ return gradientColors;
265
+ },
266
+
267
+ // 绘制圆形端点以模拟 lineCap: 'round' 效果
268
+ drawRoundEndpoints(params) {
269
+ const {
270
+ ctx,
271
+ centerX,
272
+ centerY,
273
+ innerRadius,
274
+ outerRadius,
275
+ startAngle,
276
+ endAngle,
277
+ gradientColors,
278
+ scale,
279
+ } = params;
280
+
281
+ // 计算端点半径(色环宽度的一半)
282
+ const endpointRadius = ((outerRadius - innerRadius) / 2) * scale;
283
+ // 计算色环中线半径
284
+ const midRadius = (innerRadius + (outerRadius - innerRadius) / 2) * scale;
285
+
286
+ // 起始端点(135度位置)
287
+ const startAngleRad = (startAngle * Math.PI) / 180;
288
+ const startX = centerX + midRadius * Math.cos(startAngleRad);
289
+ const startY = centerY + midRadius * Math.sin(startAngleRad);
290
+ const startColor = gradientColors[1] || gradientColors[0]; // 使用第一个颜色
291
+
292
+ // 结束端点(405度位置)
293
+ const endAngleRad = (endAngle * Math.PI) / 180;
294
+ const endX = centerX + midRadius * Math.cos(endAngleRad);
295
+ const endY = centerY + midRadius * Math.sin(endAngleRad);
296
+ const endColor =
297
+ gradientColors[gradientColors.length - 2] || gradientColors[gradientColors.length - 1]; // 使用最后一个颜色
298
+
299
+ // 重置合成操作以正常绘制端点
300
+ ctx.globalCompositeOperation = 'source-over';
301
+
302
+ // 起始端点 - 使用半圆,封闭色环起点
303
+ // 半圆应该朝向色环外侧(逆时针方向),角度范围是从色环切线的外侧到内侧
304
+ const startHalfCircleStart = startAngleRad - Math.PI; // 色环外侧
305
+ const startHalfCircleEnd = startAngleRad; // 色环内侧
306
+
307
+ ctx.beginPath();
308
+ ctx.arc(startX, startY, endpointRadius, startHalfCircleStart, startHalfCircleEnd, false);
309
+
310
+ // 使用与色环相同的径向渐变
311
+ const startGradient = ctx.createRadialGradient(
312
+ centerX,
313
+ centerY,
314
+ innerRadius * scale,
315
+ centerX,
316
+ centerY,
317
+ outerRadius * scale
318
+ );
319
+ startGradient.addColorStop(0, startColor);
320
+ startGradient.addColorStop(1, startColor);
321
+
322
+ ctx.fillStyle = startGradient;
323
+ ctx.fill();
324
+ ctx.closePath();
325
+
326
+ // 结束端点 - 使用半圆,封闭色环终点
327
+ // 半圆应该朝向色环外侧(顺时针方向),角度范围是从色环切线的内侧到外侧
328
+ const endHalfCircleStart = endAngleRad; // 色环内侧
329
+ const endHalfCircleEnd = endAngleRad + Math.PI; // 色环外侧
330
+
331
+ ctx.beginPath();
332
+ ctx.arc(endX, endY, endpointRadius, endHalfCircleStart, endHalfCircleEnd, false);
333
+
334
+ // 使用与色环相同的径向渐变
335
+ const endGradient = ctx.createRadialGradient(
336
+ centerX,
337
+ centerY,
338
+ innerRadius * scale,
339
+ centerX,
340
+ centerY,
341
+ outerRadius * scale
342
+ );
343
+ endGradient.addColorStop(0, endColor);
344
+ endGradient.addColorStop(1, endColor);
345
+
346
+ ctx.fillStyle = endGradient;
347
+ ctx.fill();
348
+ ctx.closePath();
262
349
  },
263
350
 
264
351
  // 环形色盘 降级绘制
265
352
  async renderAnnulusColorLowRank(id, radius, innerRingRadius, options = {}) {
266
353
  let canvas = null;
267
- const { touchCircleStrokeStyle, ringBorderColor, inactive, maskVisible } = options;
354
+ const {
355
+ touchCircleStrokeStyle,
356
+ ringBorderColor,
357
+ inactive,
358
+ maskVisible,
359
+ lineCap = 'round',
360
+ } = options;
268
361
  this.touchCircleStrokeStyle = touchCircleStrokeStyle;
269
362
  this.inactive = inactive;
270
363
  this.maskVisible = maskVisible;
@@ -300,7 +393,10 @@ export default Render({
300
393
  const offsetDegree = 270;
301
394
  const endDegree = startDegree + offsetDegree;
302
395
 
303
- this.drawRingWithConicGradient({
396
+ // 保存 canvas 状态(在绘制主色环之前)
397
+ ctx.save();
398
+
399
+ const gradientColors = this.drawRingWithGradientSegments({
304
400
  startAngle: startDegree,
305
401
  endAngle: endDegree,
306
402
  offsetDegree,
@@ -312,17 +408,35 @@ export default Render({
312
408
  centerX: poxCenterX,
313
409
  centerY: poxCenterY,
314
410
  ringBorderColor,
411
+ lineCap,
315
412
  });
316
413
 
414
+ // 恢复 canvas 状态(移除裁剪区域)
415
+ ctx.restore();
416
+
417
+ // 绘制圆形端点(在没有裁剪区域限制的情况下)
418
+ if (lineCap === 'round' && gradientColors && gradientColors.length > 0) {
419
+ this.drawRoundEndpoints({
420
+ ctx,
421
+ centerX: poxCenterX,
422
+ centerY: poxCenterY,
423
+ innerRadius: innerRingRadius,
424
+ outerRadius: radius,
425
+ startAngle: startDegree,
426
+ endAngle: endDegree,
427
+ gradientColors,
428
+ scale: scale, // 使用原始 scale
429
+ });
430
+ }
431
+
317
432
  ctx.scale(scale, scale);
318
433
  canvas.style.width = `${diameter}px`;
319
434
  canvas.style.height = `${diameter}px`;
320
435
  this.annulusContext = ctx;
321
436
  },
322
437
 
323
- // 环形色盘
438
+ // 环形色盘 - 统一使用降级渲染
324
439
  async renderAnnulusColor(id, radius, innerRingRadius, temp = 0, options = {}) {
325
- let canvas = null;
326
440
  const {
327
441
  touchCircleStrokeStyle = '',
328
442
  touchCircleLineWidth = 0,
@@ -331,70 +445,19 @@ export default Render({
331
445
  inactive = false,
332
446
  maskVisible = false,
333
447
  } = options || {};
448
+
449
+ // 设置实例属性
334
450
  this.touchCircleStrokeStyle = touchCircleStrokeStyle;
335
451
  this.touchCircleLineWidth = touchCircleLineWidth;
336
452
  this.hideThumb = hideThumb;
337
453
  this.inactive = inactive;
338
454
  this.maskVisible = maskVisible;
339
- try {
340
- canvas = await getCanvasById(id);
341
- } catch (error) {
342
- console.error(error);
343
- return;
344
- }
345
- if (!canvas) {
346
- console.error('canvas not found');
347
- return;
348
- }
455
+
349
456
  const { useEventChannel, eventChannelName } = options || {};
350
457
  this.useEventChannel = useEventChannel;
351
458
  this.eventChannelName = eventChannelName;
352
- canvas.width = radius * 4;
353
- canvas.height = radius * 4;
354
- const ctx = canvas.getContext('2d');
355
-
356
- const startAngle = Math.PI * 0.75;
357
- const endAngle = Math.PI * 0.25;
358
- const counterclockwise = false;
359
- ctx.beginPath();
360
- ctx.arc(
361
- radius * 2,
362
- radius * 2,
363
- innerRingRadius * 2 + (radius - innerRingRadius),
364
- startAngle,
365
- endAngle,
366
- counterclockwise
367
- );
368
-
369
- let grd = null;
370
- if (ctx.createConicGradient && lineCap === 'round') {
371
- try {
372
- grd = ctx.createConicGradient(startAngle - Math.PI * 0.1, radius * 2, radius * 2);
373
- options.colorList?.forEach(item => {
374
- grd.addColorStop(item.offset, item.color);
375
- });
376
- //设定曲线粗细度
377
- ctx.lineWidth = (radius - innerRingRadius) * 2;
378
- //给曲线着色
379
- ctx.strokeStyle = grd;
380
- //连接处样式
381
- ctx.lineCap = lineCap || 'round';
382
- //给环着色
383
- ctx.stroke();
384
- ctx.closePath();
385
- ctx.scale(2, 2);
386
- canvas.style.width = `${radius * 2}px`;
387
- canvas.style.height = `${radius * 2}px`;
388
- this.annulusContext = ctx;
389
- } catch (err) {
390
- console.error('createConicGradient:', err);
391
- }
392
- !this.hideThumb && this.renderAnnulusColorThumb(id, temp);
393
- this.callMethod('initedCanvas', {});
394
- return;
395
- }
396
459
 
397
- // 降级渲染,兼容安卓低版本机型
460
+ // 统一使用降级渲染,确保所有机型的一致性
398
461
  this.renderAnnulusColorLowRank(id, radius, innerRingRadius, options);
399
462
 
400
463
  !this.hideThumb && this.renderAnnulusColorThumb(id, temp);
@@ -446,7 +509,7 @@ export default Render({
446
509
  this.radius +
447
510
  (this.innerRingRadius + (this.radius - this.innerRingRadius) / 2) *
448
511
  Math.sin((angle * Math.PI) / 180);
449
- const { data } = ctx.getImageData(x * 2, y * 2, 1, 1);
512
+ const { data } = ctx.getImageData(Math.round(x * 2), Math.round(y * 2), 1, 1);
450
513
  const rgb = { r: data[0], g: data[1], b: data[2] };
451
514
  this.updateThumbPosition(x, y, rgb);
452
515
  const emitRes = {
@@ -507,7 +570,7 @@ export default Render({
507
570
  console.error('ctx not found');
508
571
  return;
509
572
  }
510
- const { data } = ctx.getImageData(x * 2, y * 2, 1, 1);
573
+ const { data } = ctx.getImageData(Math.round(x * 2), Math.round(y * 2), 1, 1);
511
574
  const r = data[0];
512
575
  const g = data[1];
513
576
  const b = data[2];
@@ -21,7 +21,7 @@
21
21
  border-radius: 50%;
22
22
  border: 5rpx solid rgba(255, 255, 255, 0.8);
23
23
  z-index: 99;
24
- box-shadow:0 0 7px 0 rgba(0, 0, 0, 0.16);
24
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.16);
25
25
  }
26
26
 
27
27
  .colorTipWrapper {
package/lib/hooks.js CHANGED
@@ -8,8 +8,6 @@ import { getSystemCacheInfo } from './utils';
8
8
  */
9
9
  export const useStdPx2Adapt = function (stdPx) {
10
10
  let toFixed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 2;
11
- const {
12
- screenWidth
13
- } = useMemo(() => getSystemCacheInfo(), [stdPx]);
14
- return +(stdPx * (screenWidth / 375)).toFixed(toFixed) || stdPx;
11
+ const systemInfo = useMemo(() => getSystemCacheInfo(), [stdPx]);
12
+ return +(stdPx * (systemInfo.windowWidth / 375)).toFixed(toFixed) || stdPx;
15
13
  };
@@ -6,7 +6,7 @@ type HSL = {
6
6
  };
7
7
  declare const rgbToHsl: (r: number, g: number, b: number) => HSL;
8
8
  export declare const getSystemCacheInfo: () => {
9
- screenWidth: number;
10
- screenHeight: number;
9
+ windowWidth: number;
10
+ windowHeight: number;
11
11
  };
12
12
  export { rgbToHsl, rgb2hsv, hsv2rgb };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/lamp-circle-picker",
3
- "version": "1.0.12-beta-3",
3
+ "version": "1.0.13-beta-2",
4
4
  "description": "照明缺角色环",
5
5
  "main": "lib/index",
6
6
  "files": [